*** a/src/backend/catalog/pg_aggregate.c
--- b/src/backend/catalog/pg_aggregate.c
***************
*** 332,337 **** lookup_agg_function(List *fnName,
--- 332,338 ----
  	Oid			fnOid;
  	bool		retset;
  	int			nvargs;
+ 	Oid			vatype;
  	Oid		   *true_oid_array;
  	FuncDetailCode fdresult;
  	AclResult	aclresult;
***************
*** 346,352 **** lookup_agg_function(List *fnName,
  	 */
  	fdresult = func_get_detail(fnName, NIL, NIL,
  							   nargs, input_types, false, false,
! 							   &fnOid, rettype, &retset, &nvargs,
  							   &true_oid_array, NULL);
  
  	/* only valid case is a normal function not returning a set */
--- 347,354 ----
  	 */
  	fdresult = func_get_detail(fnName, NIL, NIL,
  							   nargs, input_types, false, false,
! 							   &fnOid, rettype, &retset,
! 							   &nvargs, &vatype,
  							   &true_oid_array, NULL);
  
  	/* only valid case is a normal function not returning a set */
*** a/src/backend/parser/parse_func.c
--- b/src/backend/parser/parse_func.c
***************
*** 79,84 **** ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
--- 79,85 ----
  	Node	   *retval;
  	bool		retset;
  	int			nvargs;
+ 	Oid			vatype;
  	FuncDetailCode fdresult;
  
  	/*
***************
*** 214,220 **** ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
  	fdresult = func_get_detail(funcname, fargs, argnames, nargs,
  							   actual_arg_types,
  							   !func_variadic, true,
! 							   &funcid, &rettype, &retset, &nvargs,
  							   &declared_arg_types, &argdefaults);
  	if (fdresult == FUNCDETAIL_COERCION)
  	{
--- 215,222 ----
  	fdresult = func_get_detail(funcname, fargs, argnames, nargs,
  							   actual_arg_types,
  							   !func_variadic, true,
! 							   &funcid, &rettype, &retset,
! 							   &nvargs, &vatype,
  							   &declared_arg_types, &argdefaults);
  	if (fdresult == FUNCDETAIL_COERCION)
  	{
***************
*** 376,381 **** ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
--- 378,399 ----
  		fargs = lappend(fargs, newa);
  	}
  
+ 	/*
+ 	 * When function is called with VARIADIC labeled parameter,
+ 	 * and declared_arg_type is "ANY", then sanitize a real parameter
+ 	 * type now - should be an array.
+ 	 */
+ 	if (nargs > 0 && vatype == ANYOID && func_variadic)
+ 	{
+ 		Oid		va_arr_typid = actual_arg_types[nargs - 1];
+ 
+ 		if (!OidIsValid(get_element_type(va_arr_typid)))
+ 			ereport(ERROR,
+ 					(errcode(ERRCODE_DATATYPE_MISMATCH),
+ 					 errmsg("VARIADIC argument must be an array"),
+ 			  parser_errposition(pstate, exprLocation((Node *) llast(fargs)))));
+ 	}
+ 
  	/* build the appropriate output structure */
  	if (fdresult == FUNCDETAIL_NORMAL)
  	{
***************
*** 1015,1020 **** func_get_detail(List *funcname,
--- 1033,1039 ----
  				Oid *rettype,	/* return value */
  				bool *retset,	/* return value */
  				int *nvargs,	/* return value */
+ 				Oid *vatype,	/* return value */
  				Oid **true_typeids,		/* return value */
  				List **argdefaults)		/* optional return value */
  {
***************
*** 1233,1238 **** func_get_detail(List *funcname,
--- 1252,1258 ----
  		pform = (Form_pg_proc) GETSTRUCT(ftup);
  		*rettype = pform->prorettype;
  		*retset = pform->proretset;
+ 		*vatype = pform->provariadic;
  		/* fetch default args if caller wants 'em */
  		if (argdefaults && best_candidate->ndargs > 0)
  		{
*** a/src/backend/utils/adt/ruleutils.c
--- b/src/backend/utils/adt/ruleutils.c
***************
*** 8550,8555 **** generate_function_name(Oid funcid, int nargs, List *argnames, Oid *argtypes,
--- 8550,8556 ----
  	Oid			p_rettype;
  	bool		p_retset;
  	int			p_nvargs;
+ 	Oid			p_vatype;
  	Oid		   *p_true_typeids;
  
  	proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
***************
*** 8600,8606 **** generate_function_name(Oid funcid, int nargs, List *argnames, Oid *argtypes,
  							   NIL, argnames, nargs, argtypes,
  							   !use_variadic, true,
  							   &p_funcid, &p_rettype,
! 							   &p_retset, &p_nvargs, &p_true_typeids, NULL);
  	if ((p_result == FUNCDETAIL_NORMAL ||
  		 p_result == FUNCDETAIL_AGGREGATE ||
  		 p_result == FUNCDETAIL_WINDOWFUNC) &&
--- 8601,8608 ----
  							   NIL, argnames, nargs, argtypes,
  							   !use_variadic, true,
  							   &p_funcid, &p_rettype,
! 							   &p_retset, &p_nvargs, &p_vatype,
! 							   &p_true_typeids, NULL);
  	if ((p_result == FUNCDETAIL_NORMAL ||
  		 p_result == FUNCDETAIL_AGGREGATE ||
  		 p_result == FUNCDETAIL_WINDOWFUNC) &&
*** a/src/backend/utils/adt/varlena.c
--- b/src/backend/utils/adt/varlena.c
***************
*** 3811,3817 **** concat_internal(const char *sepstr, int argidx,
  	 */
  	if (get_fn_expr_variadic(fcinfo->flinfo))
  	{
- 		Oid			arr_typid;
  		ArrayType  *arr;
  
  		/* Should have just the one argument */
--- 3811,3816 ----
***************
*** 3821,3841 **** concat_internal(const char *sepstr, int argidx,
  		if (PG_ARGISNULL(argidx))
  			return NULL;
  
! 		/*
! 		 * Non-null argument had better be an array.  The parser doesn't
! 		 * enforce this for VARIADIC ANY functions (maybe it should?), so that
! 		 * check uses ereport not just elog.
! 		 */
! 		arr_typid = get_fn_expr_argtype(fcinfo->flinfo, argidx);
! 		if (!OidIsValid(arr_typid))
! 			elog(ERROR, "could not determine data type of concat() input");
! 
! 		if (!OidIsValid(get_element_type(arr_typid)))
! 			ereport(ERROR,
! 					(errcode(ERRCODE_DATATYPE_MISMATCH),
! 					 errmsg("VARIADIC argument must be an array")));
  
- 		/* OK, safe to fetch the array value */
  		arr = PG_GETARG_ARRAYTYPE_P(argidx);
  
  		/*
--- 3820,3828 ----
  		if (PG_ARGISNULL(argidx))
  			return NULL;
  
! 		/* Non-null argument had better be an array */
! 		Assert(OidIsValid(get_element_type(get_fn_expr_argtype(fcinfo->flinfo, argidx))));
  
  		arr = PG_GETARG_ARRAYTYPE_P(argidx);
  
  		/*
***************
*** 4024,4030 **** text_format(PG_FUNCTION_ARGS)
  	/* If argument is marked VARIADIC, expand array into elements */
  	if (get_fn_expr_variadic(fcinfo->flinfo))
  	{
- 		Oid			arr_typid;
  		ArrayType  *arr;
  		int16		elmlen;
  		bool		elmbyval;
--- 4011,4016 ----
***************
*** 4039,4059 **** text_format(PG_FUNCTION_ARGS)
  			nitems = 0;
  		else
  		{
! 			/*
! 			 * Non-null argument had better be an array.  The parser doesn't
! 			 * enforce this for VARIADIC ANY functions (maybe it should?), so
! 			 * that check uses ereport not just elog.
! 			 */
! 			arr_typid = get_fn_expr_argtype(fcinfo->flinfo, 1);
! 			if (!OidIsValid(arr_typid))
! 				elog(ERROR, "could not determine data type of format() input");
! 
! 			if (!OidIsValid(get_element_type(arr_typid)))
! 				ereport(ERROR,
! 						(errcode(ERRCODE_DATATYPE_MISMATCH),
! 						 errmsg("VARIADIC argument must be an array")));
  
- 			/* OK, safe to fetch the array value */
  			arr = PG_GETARG_ARRAYTYPE_P(1);
  
  			/* Get info about array element type */
--- 4025,4033 ----
  			nitems = 0;
  		else
  		{
! 			/* Non-null argument had better be an array */
! 			Assert(OidIsValid(get_element_type(get_fn_expr_argtype(fcinfo->flinfo, 1))));
  
  			arr = PG_GETARG_ARRAYTYPE_P(1);
  
  			/* Get info about array element type */
*** a/src/include/parser/parse_func.h
--- b/src/include/parser/parse_func.h
***************
*** 53,60 **** extern FuncDetailCode func_get_detail(List *funcname,
  				int nargs, Oid *argtypes,
  				bool expand_variadic, bool expand_defaults,
  				Oid *funcid, Oid *rettype,
! 				bool *retset, int *nvargs, Oid **true_typeids,
! 				List **argdefaults);
  
  extern int func_match_argtypes(int nargs,
  					Oid *input_typeids,
--- 53,60 ----
  				int nargs, Oid *argtypes,
  				bool expand_variadic, bool expand_defaults,
  				Oid *funcid, Oid *rettype,
! 				bool *retset, int *nvargs, Oid *vatype,
! 				Oid **true_typeids, List **argdefaults);
  
  extern int func_match_argtypes(int nargs,
  					Oid *input_typeids,
*** a/src/test/regress/expected/text.out
--- b/src/test/regress/expected/text.out
***************
*** 149,161 **** select concat_ws(',', variadic array[1,2,3]);
   1,2,3
  (1 row)
  
! select concat_ws(',', variadic NULL);
   concat_ws 
  -----------
   
  (1 row)
  
! select concat(variadic NULL) is NULL;
   ?column? 
  ----------
   t
--- 149,161 ----
   1,2,3
  (1 row)
  
! select concat_ws(',', variadic NULL::int[]);
   concat_ws 
  -----------
   
  (1 row)
  
! select concat(variadic NULL::int[]) is NULL;
   ?column? 
  ----------
   t
***************
*** 170,175 **** select concat(variadic '{}'::int[]) = '';
--- 170,177 ----
  --should fail
  select concat_ws(',', variadic 10);
  ERROR:  VARIADIC argument must be an array
+ LINE 1: select concat_ws(',', variadic 10);
+                                        ^
  /*
   * format
   */
***************
*** 313,320 **** select format('%2$s, %1$s', variadic array[1, 2]);
   2, 1
  (1 row)
  
! -- variadic argument can be NULL, but should not be referenced
! select format('Hello', variadic NULL);
   format 
  --------
   Hello
--- 315,322 ----
   2, 1
  (1 row)
  
! -- variadic argument can be array type NULL, but should not be referenced
! select format('Hello', variadic NULL::int[]);
   format 
  --------
   Hello
*** a/src/test/regress/sql/text.sql
--- b/src/test/regress/sql/text.sql
***************
*** 47,54 **** select quote_literal(e'\\');
  -- check variadic labeled argument
  select concat(variadic array[1,2,3]);
  select concat_ws(',', variadic array[1,2,3]);
! select concat_ws(',', variadic NULL);
! select concat(variadic NULL) is NULL;
  select concat(variadic '{}'::int[]) = '';
  --should fail
  select concat_ws(',', variadic 10);
--- 47,54 ----
  -- check variadic labeled argument
  select concat(variadic array[1,2,3]);
  select concat_ws(',', variadic array[1,2,3]);
! select concat_ws(',', variadic NULL::int[]);
! select concat(variadic NULL::int[]) is NULL;
  select concat(variadic '{}'::int[]) = '';
  --should fail
  select concat_ws(',', variadic 10);
***************
*** 92,99 **** select format('%s, %s', variadic array[true, false]::text[]);
  -- check variadic with positional placeholders
  select format('%2$s, %1$s', variadic array['first', 'second']);
  select format('%2$s, %1$s', variadic array[1, 2]);
! -- variadic argument can be NULL, but should not be referenced
! select format('Hello', variadic NULL);
  -- variadic argument allows simulating more than FUNC_MAX_ARGS parameters
  select format(string_agg('%s',','), variadic array_agg(i))
  from generate_series(1,200) g(i);
--- 92,99 ----
  -- check variadic with positional placeholders
  select format('%2$s, %1$s', variadic array['first', 'second']);
  select format('%2$s, %1$s', variadic array[1, 2]);
! -- variadic argument can be array type NULL, but should not be referenced
! select format('Hello', variadic NULL::int[]);
  -- variadic argument allows simulating more than FUNC_MAX_ARGS parameters
  select format(string_agg('%s',','), variadic array_agg(i))
  from generate_series(1,200) g(i);
