*** a/src/backend/catalog/pg_aggregate.c
--- b/src/backend/catalog/pg_aggregate.c
***************
*** 344,351 **** 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 */
  	if (fdresult != FUNCDETAIL_NORMAL || !OidIsValid(fnOid))
--- 344,351 ----
  	 */
  	fdresult = func_get_detail(fnName, NIL, NIL,
  							   nargs, input_types, false, false,
! 							   &fnOid, rettype, &retset, NULL,
! 							   &nvargs, &true_oid_array, NULL);
  
  	/* only valid case is a normal function not returning a set */
  	if (fdresult != FUNCDETAIL_NORMAL || !OidIsValid(fnOid))
*** a/src/backend/executor/execQual.c
--- b/src/backend/executor/execQual.c
***************
*** 1728,1733 **** restart:
--- 1728,1843 ----
  	}
  
  	/*
+ 	 * this is support for variadic function corner case - using variadic argument
+ 	 * with VARIADIC modifier when variadic "any" function is called. In this case
+ 	 * we have to create short lived flinfo and fcinfo, because function descriptors
+ 	 * can be different in any call of variadic function - depends on content of
+ 	 * variadic array argument.
+ 	 */
+ 	if (IsA(fcache->xprstate.expr, FuncExpr) && ((FuncExpr *) fcache->xprstate.expr)->merge_vararg)
+ 	{
+ 		FmgrInfo sfinfo;			/* short lived fake finfo */
+ 		FunctionCallInfo	scinfo;		/* short lived fake fcinfo */
+ 		FuncExpr sfexpr;			/* short lived fake fcinfo */
+ 		MemoryContext		oldContext;
+ 		Oid				vararg_type;
+ 		Oid				elem_type;
+ 		bool				elem_typbyval;
+ 		int16				elem_typlen;
+ 		char				elem_typalign;
+ 		ArrayType		*arr;
+ 		ArrayIterator		iterator;
+ 		List		*params_exprs;
+ 		ListCell	*lc;
+ 		int		n;
+ 		Datum			value;
+ 		bool			isnull;
+ 		int			slice;
+ 		FuncExpr			*fexpr = (FuncExpr *) fcache->xprstate.expr;
+ 
+ 		/* sanity check, a variadic argument should be a array */
+ 		if (fcinfo->argnull[fcinfo->nargs - 1])
+ 			ereport(ERROR,
+ 					(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
+ 					 errmsg("variadic argument cannot be null")));
+ 
+ 		vararg_type = get_fn_expr_argtype(fcinfo->flinfo, fcinfo->nargs - 1);
+ 		if (!OidIsValid(vararg_type))
+ 			ereport(ERROR,
+ 					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ 					 errmsg("could not determinate variadic argument data type")));
+ 		if (!OidIsValid(get_element_type(vararg_type)))
+ 			ereport(ERROR,
+ 					(errcode(ERRCODE_DATATYPE_MISMATCH),
+ 					 errmsg("variadic argument should be an array")));
+ 
+ 		/* switch to short lived per-tuple context for node's copies */
+ 		oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
+ 
+ 		arr = DatumGetArrayTypeP(fcinfo->arg[fcinfo->nargs - 1]);
+ 		slice = ARR_NDIM(arr) > 1 ? ARR_NDIM(arr) - 1 : 0;
+ 		elem_type = slice > 0 ? vararg_type : ARR_ELEMTYPE(arr);
+ 
+ 		/* ToDo: use element_type depends for dimensions */
+ 		get_typlenbyvalalign(elem_type,
+ 							 &elem_typlen,
+ 							 &elem_typbyval,
+ 							 &elem_typalign);
+ 
+ 		scinfo = (FunctionCallInfo) palloc(sizeof(FunctionCallInfoData));
+ 
+ 		/* create short lived copies of fmgr data */
+ 		fmgr_info_copy(&sfinfo, fcinfo->flinfo, fcinfo->flinfo->fn_mcxt);
+ 		memcpy(scinfo, fcinfo, sizeof(FunctionCallInfoData));
+ 		scinfo->flinfo = &sfinfo;
+ 
+ 		iterator = array_create_iterator(arr, slice);
+ 
+ 		/*
+ 		 * we have to create short lived fn_expr because variadic 
+ 		 * "any" functions takes types from expression nodes via get_fn_expr_argtype.
+ 		 */
+ 		n = 0;
+ 		params_exprs = NIL;
+ 		foreach(lc, fexpr->args)
+ 		{
+ 			/* don't copy last "variadic argument */
+ 			if (n >= fcinfo->nargs - 1)
+ 				break;
+ 
+ 			params_exprs = lappend(params_exprs, lc->data.ptr_value);
+ 			n++;
+ 		}
+ 
+ 		while (array_iterate(iterator, &value, &isnull))
+ 		{
+ 			/* replace variadic argument */
+ 			scinfo->arg[n] = value;
+ 			scinfo->argnull[n] = isnull;
+ 
+ 			params_exprs = lappend(params_exprs, makeConst(elem_type,
+ 										    -1,
+ 										    scinfo->fncollation,
+ 										    elem_typlen,
+ 										    value,
+ 										    isnull,
+ 										    elem_typbyval));
+ 			n++;
+ 		}
+ 
+ 		array_free_iterator(iterator);
+ 
+ 		memcpy(&sfexpr, fexpr, sizeof(FuncExpr));
+ 		sfexpr.args = params_exprs;
+ 		sfinfo.fn_expr = (fmNodePtr) &sfexpr;
+ 
+ 		scinfo->nargs = n;
+ 		fcinfo = scinfo;
+ 
+ 		MemoryContextSwitchTo(oldContext);
+ 	}
+ 
+ 	/*
  	 * Now call the function, passing the evaluated parameter values.
  	 */
  	if (fcache->func.fn_retset || hasSetArg)
*** a/src/backend/nodes/copyfuncs.c
--- b/src/backend/nodes/copyfuncs.c
***************
*** 1194,1199 **** _copyFuncExpr(const FuncExpr *from)
--- 1194,1200 ----
  	COPY_SCALAR_FIELD(funcid);
  	COPY_SCALAR_FIELD(funcresulttype);
  	COPY_SCALAR_FIELD(funcretset);
+ 	COPY_SCALAR_FIELD(merge_vararg);
  	COPY_SCALAR_FIELD(funcformat);
  	COPY_SCALAR_FIELD(funccollid);
  	COPY_SCALAR_FIELD(inputcollid);
*** a/src/backend/nodes/equalfuncs.c
--- b/src/backend/nodes/equalfuncs.c
***************
*** 239,244 **** _equalFuncExpr(const FuncExpr *a, const FuncExpr *b)
--- 239,245 ----
  	COMPARE_SCALAR_FIELD(funcid);
  	COMPARE_SCALAR_FIELD(funcresulttype);
  	COMPARE_SCALAR_FIELD(funcretset);
+ 	COMPARE_SCALAR_FIELD(merge_vararg);
  	COMPARE_COERCIONFORM_FIELD(funcformat);
  	COMPARE_SCALAR_FIELD(funccollid);
  	COMPARE_SCALAR_FIELD(inputcollid);
*** a/src/backend/nodes/makefuncs.c
--- b/src/backend/nodes/makefuncs.c
***************
*** 461,466 **** makeFuncExpr(Oid funcid, Oid rettype, List *args,
--- 461,467 ----
  	funcexpr->funcid = funcid;
  	funcexpr->funcresulttype = rettype;
  	funcexpr->funcretset = false;		/* only allowed case here */
+ 	funcexpr->merge_vararg = false;		/* only allowed case here */
  	funcexpr->funcformat = fformat;
  	funcexpr->funccollid = funccollid;
  	funcexpr->inputcollid = inputcollid;
*** a/src/backend/nodes/outfuncs.c
--- b/src/backend/nodes/outfuncs.c
***************
*** 1000,1005 **** _outFuncExpr(StringInfo str, const FuncExpr *node)
--- 1000,1006 ----
  	WRITE_OID_FIELD(funcid);
  	WRITE_OID_FIELD(funcresulttype);
  	WRITE_BOOL_FIELD(funcretset);
+ 	WRITE_BOOL_FIELD(merge_vararg);
  	WRITE_ENUM_FIELD(funcformat, CoercionForm);
  	WRITE_OID_FIELD(funccollid);
  	WRITE_OID_FIELD(inputcollid);
*** a/src/backend/nodes/readfuncs.c
--- b/src/backend/nodes/readfuncs.c
***************
*** 537,542 **** _readFuncExpr(void)
--- 537,543 ----
  	READ_OID_FIELD(funcid);
  	READ_OID_FIELD(funcresulttype);
  	READ_BOOL_FIELD(funcretset);
+ 	READ_BOOL_FIELD(merge_vararg);
  	READ_ENUM_FIELD(funcformat, CoercionForm);
  	READ_OID_FIELD(funccollid);
  	READ_OID_FIELD(inputcollid);
*** a/src/backend/optimizer/util/clauses.c
--- b/src/backend/optimizer/util/clauses.c
***************
*** 2330,2335 **** eval_const_expressions_mutator(Node *node,
--- 2330,2336 ----
  				newexpr->funcid = expr->funcid;
  				newexpr->funcresulttype = expr->funcresulttype;
  				newexpr->funcretset = expr->funcretset;
+ 				newexpr->merge_vararg = expr->merge_vararg;
  				newexpr->funcformat = expr->funcformat;
  				newexpr->funccollid = expr->funccollid;
  				newexpr->inputcollid = expr->inputcollid;
***************
*** 3625,3630 **** simplify_function(Oid funcid, Oid result_type, int32 result_typmod,
--- 3626,3632 ----
  		fexpr.funcid = funcid;
  		fexpr.funcresulttype = result_type;
  		fexpr.funcretset = func_form->proretset;
+ 		fexpr.merge_vararg = false;
  		fexpr.funcformat = COERCE_EXPLICIT_CALL;
  		fexpr.funccollid = result_collid;
  		fexpr.inputcollid = input_collid;
***************
*** 3959,3964 **** evaluate_function(Oid funcid, Oid result_type, int32 result_typmod,
--- 3961,3967 ----
  	newexpr->funcid = funcid;
  	newexpr->funcresulttype = result_type;
  	newexpr->funcretset = false;
+ 	newexpr->merge_vararg = false;
  	newexpr->funcformat = COERCE_EXPLICIT_CALL;	/* doesn't matter */
  	newexpr->funccollid = result_collid;		/* doesn't matter */
  	newexpr->inputcollid = input_collid;
***************
*** 4089,4094 **** inline_function(Oid funcid, Oid result_type, Oid result_collid,
--- 4092,4098 ----
  	fexpr->funcid = funcid;
  	fexpr->funcresulttype = result_type;
  	fexpr->funcretset = false;
+ 	fexpr->merge_vararg = false;			/* SQL cannot be variadic "any" */
  	fexpr->funcformat = COERCE_EXPLICIT_CALL;	/* doesn't matter */
  	fexpr->funccollid = result_collid;	/* doesn't matter */
  	fexpr->inputcollid = input_collid;
*** a/src/backend/parser/parse_func.c
--- b/src/backend/parser/parse_func.c
***************
*** 78,83 **** ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
--- 78,84 ----
  	List	   *argdefaults;
  	Node	   *retval;
  	bool		retset;
+ 	bool		merge_vararg;
  	int			nvargs;
  	FuncDetailCode fdresult;
  
***************
*** 214,221 **** 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, &merge_vararg,
! 							   &nvargs, &declared_arg_types, &argdefaults);
  	if (fdresult == FUNCDETAIL_COERCION)
  	{
  		/*
***************
*** 384,389 **** ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
--- 385,391 ----
  		funcexpr->funcid = funcid;
  		funcexpr->funcresulttype = rettype;
  		funcexpr->funcretset = retset;
+ 		funcexpr->merge_vararg = merge_vararg;
  		funcexpr->funcformat = COERCE_EXPLICIT_CALL;
  		/* funccollid and inputcollid will be set by parse_collate.c */
  		funcexpr->args = fargs;
***************
*** 1001,1006 **** func_select_candidate(int nargs,
--- 1003,1017 ----
   * they don't need that check made.  Note also that when fargnames isn't NIL,
   * the fargs list must be passed if the caller wants actual argument position
   * information to be returned into the NamedArgExpr nodes.
+  *
+  * Special use case is a call variadic function with "any" variadic parameter and
+  * with variadic argument - argument market VARIADIC modifier. Variadic "any"
+  * function expect unpacked variadic arguments passed in fcinfo->args like usual
+  * parameter. Others variadic functions expect variadic argument as a array. So
+  * when we don't wont expand variadic parameter and we have variadic "any"
+  * function, we have to unpack a array to fcinfo->args array and we have to
+  * create short life FmgrInfo fake structure. When this use case is identified,
+  * then output in merge_vararg is true.
   */
  FuncDetailCode
  func_get_detail(List *funcname,
***************
*** 1013,1018 **** func_get_detail(List *funcname,
--- 1024,1030 ----
  				Oid *funcid,	/* return value */
  				Oid *rettype,	/* return value */
  				bool *retset,	/* return value */
+ 				bool *merge_vararg,	/* optional return value */
  				int *nvargs,	/* return value */
  				Oid **true_typeids,		/* return value */
  				List **argdefaults)		/* optional return value */
***************
*** 1301,1306 **** func_get_detail(List *funcname,
--- 1313,1322 ----
  				*argdefaults = defaults;
  			}
  		}
+ 
+ 		if (merge_vararg != NULL)
+ 			*merge_vararg = !expand_variadic && pform->provariadic == ANYOID;
+ 
  		if (pform->proisagg)
  			result = FUNCDETAIL_AGGREGATE;
  		else if (pform->proiswindow)
*** a/src/backend/utils/adt/ruleutils.c
--- b/src/backend/utils/adt/ruleutils.c
***************
*** 7437,7443 **** generate_function_name(Oid funcid, int nargs, List *argnames,
  							   NIL, argnames, nargs, argtypes,
  							   !OidIsValid(procform->provariadic), 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) &&
--- 7437,7443 ----
  							   NIL, argnames, nargs, argtypes,
  							   !OidIsValid(procform->provariadic), true,
  							   &p_funcid, &p_rettype,
! 							   &p_retset, NULL, &p_nvargs, &p_true_typeids, NULL);
  	if ((p_result == FUNCDETAIL_NORMAL ||
  		 p_result == FUNCDETAIL_AGGREGATE ||
  		 p_result == FUNCDETAIL_WINDOWFUNC) &&
*** a/src/include/nodes/primnodes.h
--- b/src/include/nodes/primnodes.h
***************
*** 340,345 **** typedef struct FuncExpr
--- 340,347 ----
  	Oid			funcid;			/* PG_PROC OID of the function */
  	Oid			funcresulttype; /* PG_TYPE OID of result value */
  	bool		funcretset;		/* true if function returns set */
+ 	bool		merge_vararg;		/* if true, then do unpack last array argument */
+ 									/* to fmgr args */
  	CoercionForm funcformat;	/* how to display this function call */
  	Oid			funccollid;		/* OID of collation of result */
  	Oid			inputcollid;	/* OID of collation that function should use */
*** a/src/include/parser/parse_func.h
--- b/src/include/parser/parse_func.h
***************
*** 53,59 **** 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,
--- 53,60 ----
  				int nargs, Oid *argtypes,
  				bool expand_variadic, bool expand_defaults,
  				Oid *funcid, Oid *rettype,
! 				bool *retset, bool *merge_vararg,
! 				int *nvargs, Oid **true_typeids,
  				List **argdefaults);
  
  extern int func_match_argtypes(int nargs,
*** a/src/test/regress/expected/text.out
--- b/src/test/regress/expected/text.out
***************
*** 228,234 **** select format('%1$', 1);
  ERROR:  unterminated conversion specifier
  select format('%1$1', 1);
  ERROR:  unrecognized conversion specifier "1"
! --checkk mix of positional and ordered placeholders
  select format('Hello %s %1$s %s', 'World', 'Hello again');
              format             
  -------------------------------
--- 228,234 ----
  ERROR:  unterminated conversion specifier
  select format('%1$1', 1);
  ERROR:  unrecognized conversion specifier "1"
! --check mix of positional and ordered placeholders
  select format('Hello %s %1$s %s', 'World', 'Hello again');
              format             
  -------------------------------
***************
*** 241,243 **** select format('Hello %s %s, %2$s %2$s', 'World', 'Hello again');
--- 241,289 ----
   Hello World Hello again, Hello again Hello again
  (1 row)
  
+ -- check pass variadic argument
+ select format('%s, %s', variadic array['Hello','World']);
+     format    
+ --------------
+  Hello, World
+ (1 row)
+ 
+ -- multidimensional array is supported
+ select format('%s, %s', variadic array[['Nazdar','Svete'],['Hello','World']]);
+             format             
+ -------------------------------
+  {Nazdar,Svete}, {Hello,World}
+ (1 row)
+ 
+ -- check others datatypes
+ select format('%s, %s', variadic array[1, 2]);
+  format 
+ --------
+  1, 2
+ (1 row)
+ 
+ select format('%s, %s', variadic array[true, false]);
+  format 
+ --------
+  t, f
+ (1 row)
+ 
+ select format('%s, %s', variadic array[true, false]::text[]);
+    format    
+ -------------
+  true, false
+ (1 row)
+ 
+ -- check positional placeholders
+ select format('%2$s, %1$s', variadic array['first', 'second']);
+     format     
+ ---------------
+  second, first
+ (1 row)
+ 
+ select format('%2$s, %1$s', variadic array[1, 2]);
+  format 
+ --------
+  2, 1
+ (1 row)
+ 
*** a/src/test/regress/sql/text.sql
--- b/src/test/regress/sql/text.sql
***************
*** 73,78 **** select format('%1$s %13$s', 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12);
  select format('%1s', 1);
  select format('%1$', 1);
  select format('%1$1', 1);
! --checkk mix of positional and ordered placeholders
  select format('Hello %s %1$s %s', 'World', 'Hello again');
  select format('Hello %s %s, %2$s %2$s', 'World', 'Hello again');
--- 73,91 ----
  select format('%1s', 1);
  select format('%1$', 1);
  select format('%1$1', 1);
! --check mix of positional and ordered placeholders
  select format('Hello %s %1$s %s', 'World', 'Hello again');
  select format('Hello %s %s, %2$s %2$s', 'World', 'Hello again');
+ 
+ -- check pass variadic argument
+ select format('%s, %s', variadic array['Hello','World']);
+ -- multidimensional array is supported
+ select format('%s, %s', variadic array[['Nazdar','Svete'],['Hello','World']]);
+ -- check others datatypes
+ select format('%s, %s', variadic array[1, 2]);
+ select format('%s, %s', variadic array[true, false]);
+ select format('%s, %s', variadic array[true, false]::text[]);
+ 
+ -- check positional placeholders
+ select format('%2$s, %1$s', variadic array['first', 'second']);
+ select format('%2$s, %1$s', variadic array[1, 2]);
