diff --git a/doc/src/sgml/xfunc.sgml b/doc/src/sgml/xfunc.sgml
index 3c8ce43..c6ece84 100644
*** a/doc/src/sgml/xfunc.sgml
--- b/doc/src/sgml/xfunc.sgml
*************** CREATE FUNCTION test(int, int) RETURNS i
*** 1101,1106 ****
--- 1101,1222 ----
     </para>
    </sect1>
  
+   <sect1 id="xfunc-notation">
+    <title>Positional, Mixed and Named notation</title>
+ 
+    <indexterm zone="xfunc-notation">
+     <primary>notation</primary>
+     <secondary>functions</secondary>
+    </indexterm>
+ 
+    <para>
+     Functions with named parameters should by called with <firstterm>mixed</firstterm> 
+     or <firstterm>named notation</firstterm>. Any typical use expects <firstterm>posiotional 
+     notation</firstterm>, when an order of parameters is important. For named notation 
+     is important name of parameters. You can mix both notation - result is mixed notation.
+     Some first n parameters should be entered in positional parameters
+     and others in named notation. You don't need pass parameters than has
+     default value.
+ <programlisting>
+ CREATE FUNCTION fx(a int, b int, m int = 1, o int = 0) RETURNS int AS $$
+     SELECT ($1 + $2) * $3 + $4
+ $$ LANGUAGE SQL;
+ </programlisting>
+    Function <function>fx</function> has obligatory parameters: <literal>a</literal> and
+    <literal>b</literal> and optional parameters: <literal>m</literal> and <literal>o</literal>.
+    This function should be called with positional parameters. See <xref
+      linkend="xfunc-sql-parameter-defaults"> for a more detailed explanation of calling
+      function with default values.
+    </para>
+    
+    <sect2 id="xfunc-notations-positional">
+     <title>Using positional notation</title>
+ 
+    <indexterm>
+     <primary>function</primary>
+     <secondary>positional notation</secondary>
+    </indexterm>
+ 
+     <para>
+ <screen>
+ SELECT fx(10,20);
+  fx 
+ ----
+  30
+ (1 row)
+   
+ SELECT fx(10,20,2,50);
+   fx  
+ -----
+  110
+ (1 row)
+ </screen>
+     </para>
+   </sect2>
+ 
+   <sect2 id="xfunc-notations-named">
+     <title>Using named notation</title>
+ 
+    <indexterm>
+     <primary>function</primary>
+     <secondary>named notation</secondary>
+    </indexterm>
+ 
+     <para>
+ <screen>
+ SELECT fx(10 as a, 20 as b);
+  fx 
+ ----
+  30
+ (1 row)
+ 
+ SELECT fx(20 as b, 10 as a);
+  fx 
+ ----
+  30
+ (1 row)
+ 
+ SELECT fx(20 as b, 10 as a, 50 as o);
+  fx 
+ ----
+  80
+ (1 row)
+ </screen>
+     </para>
+   </sect2>
+  
+   <sect2 id="xfunc-notations-mixed">
+     <title>Using mixed notation</title>
+ 
+    <indexterm>
+     <primary>function</primary>
+     <secondary>mixed notation</secondary>
+    </indexterm>
+ 
+     <para>
+ <screen>
+ SELECT fx(10,20, 50 as o);
+  fx 
+ ----
+  80
+ (1 row)
+ 
+ SELECT fx(10,20, 10 as m);
+  fx  
+ -----
+  300
+ (1 row)
+ 
+ SELECT fx(10,20, 50 as o, 2 as m);
+  fx  
+ -----
+  110
+ (1 row)
+ </screen>
+     </para>
+    </sect2>
+   </sect1>
+ 
    <sect1 id="xfunc-volatility">
     <title>Function Volatility Categories</title>
  
diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c
index 2b0cb35..714d337 100644
*** a/src/backend/catalog/namespace.c
--- b/src/backend/catalog/namespace.c
***************
*** 36,41 ****
--- 36,42 ----
  #include "catalog/pg_ts_template.h"
  #include "catalog/pg_type.h"
  #include "commands/dbcommands.h"
+ #include "funcapi.h"
  #include "miscadmin.h"
  #include "nodes/makefuncs.h"
  #include "parser/parse_func.h"
*************** TypeIsVisible(Oid typid)
*** 603,610 ****
   * The caller might end up discarding such an entry anyway, but if it selects
   * such an entry it should react as though the call were ambiguous.
   */
  FuncCandidateList
! FuncnameGetCandidates(List *names, int nargs,
  					  bool expand_variadic, bool expand_defaults)
  {
  	FuncCandidateList resultList = NULL;
--- 604,723 ----
   * The caller might end up discarding such an entry anyway, but if it selects
   * such an entry it should react as though the call were ambiguous.
   */
+ static bool
+ VerifyCandidateNamedNotation(HeapTuple proctup, int pronargs, int nargs, List *argnames, short int pronargdefaults,
+ 						bool *use_defaults, short int **param_map)
+ {
+ 	Datum		proargnames;
+ 	Oid			*p_argtypes;
+ 	char			**p_argnames;
+ 	char			*p_argmodes;
+ 	bool	isnull;
+ 	int			pronallargs;
+ 	int	i;
+ 	int		pp;			/* proargs position */
+ 	int		ap;			/* args position */
+ 	ListCell	*lc;
+ 	FuncCallNotation		used_notation = POSITIONAL_NOTATION; 		/* used only for asertion */
+ 
+ #define UNDEFINED_PARAMETER		-1
+ 
+ 	Assert(argnames != NIL);
+ 
+ 	/* Ignore if not enough default expressions */
+ 	if (nargs + pronargdefaults < pronargs)
+ 		return false;
+ 
+ 	/* check proargnames */
+ 	proargnames = SysCacheGetAttr(PROCOID, proctup,
+ 							    Anum_pg_proc_proargnames, 
+ 							    &isnull);
+ 	if (isnull)
+ 		return false;
+ 
+ 	pronallargs = get_func_arg_info(proctup, &p_argtypes, &p_argnames, &p_argmodes);
+ 	Assert(p_argnames != NULL);
+ 
+ 	/* 
+ 	 * An number less or equal nargs means some arg,
+ 	 * an number greather than nargs means some default.
+ 	*/
+ 	*param_map = palloc(pronargs * sizeof(short int));
+ 	for (i = 0; i < pronargs; i++)
+ 		(*param_map)[i] = UNDEFINED_PARAMETER;
+ 
+ 	ap = 0;
+ 	foreach(lc, argnames)
+ 	{
+ 		char *argname = (char *) lfirst(lc);
+ 		bool	found;
+
+ 		if (argname != NULL)
+ 		{
+ 			pp = 0;
+ 			found = false;
+ 			for (i = 0; i < pronallargs; i++)
+ 			{
+ 				/* skip all out params */
+ 				if (p_argmodes && (p_argmodes[i] != FUNC_PARAM_IN && p_argmodes[i] != FUNC_PARAM_INOUT))
+ 					continue;
+ 				if (p_argnames[i] && strcmp(p_argnames[i], argname) == 0)
+ 				{
+ 					/* protect under twice entry same param via positional and named notation */
+ 					if ((*param_map)[pp] != UNDEFINED_PARAMETER)
+ 						ereport(ERROR,
+ 								(errcode(ERRCODE_SYNTAX_ERROR),
+ 								 errmsg("named parameter \"%s\" overlaps %d. positional parameter", argname, i + 1)));
+
+ 					found = true;
+ 					(*param_map)[pp] = ap;		/* named parameter */
+ 					break;
+ 				}
+ 				/* increase only for IN and INOUT args */
+ 				pp++;
+ 			}
+ 			/* any name isn't in proargnames, fast leaving */
+ 			if (!found)
+ 				return false;
+ 
+ 			used_notation = NAMED_NOTATION;
+ 		}
+ 		else
+ 		{
+ 			Assert(used_notation == POSITIONAL_NOTATION);
+
+ 			(*param_map)[ap] = ap;				/* positional parameter */
+ 		}
+ 		ap++;
+ 	}
+ 
+ 	Assert(used_notation == NAMED_NOTATION);
+ 
+ 	/* Have we check defaults? */
+ 	if (nargs < pronargs)
+ 	{
+ 		int first_arg_with_default = pronargs - pronargdefaults;
+ 
+ 		for (i = 0; i < pronargs; i++)
+ 		{
+ 			/* When we still missing param and no default is available, exit */
+ 			if ((*param_map)[i] == UNDEFINED_PARAMETER)
+ 			{
+ 				if (i < first_arg_with_default)
+ 					return false;
+ 				/* offset to defaults + nargs */
+ 				(*param_map)[i] = i - first_arg_with_default + nargs;
+ 			}
+ 		}
+ 		*use_defaults = true;
+ 	}
+ 
+ 	return true;
+ }
+ 
+  
  FuncCandidateList
! FuncnameGetCandidates(List *names, int nargs, List *argnames,
  					  bool expand_variadic, bool expand_defaults)
  {
  	FuncCandidateList resultList = NULL;
*************** FuncnameGetCandidates(List *names, int n
*** 645,688 ****
  		int			pronargs = procform->pronargs;
  		int			effective_nargs;
  		int			pathpos = 0;
! 		bool		variadic;
! 		bool		use_defaults;
! 		Oid			va_elem_type;
  		FuncCandidateList newResult;
  
! 		/*
! 		 * Check if function is variadic, and get variadic element type if so.
! 		 * If expand_variadic is false, we should just ignore variadic-ness.
! 		 */
! 		if (pronargs <= nargs && expand_variadic)
  		{
! 			va_elem_type = procform->provariadic;
! 			variadic = OidIsValid(va_elem_type);
! 			any_special |= variadic;
  		}
  		else
  		{
! 			va_elem_type = InvalidOid;
! 			variadic = false;
! 		}
  
! 		/*
! 		 * Check if function can match by using parameter defaults.
! 		 */
! 		if (pronargs > nargs && expand_defaults)
! 		{
! 			/* Ignore if not enough default expressions */
! 			if (nargs + procform->pronargdefaults < pronargs)
  				continue;
- 			use_defaults = true;
- 			any_special = true;
  		}
- 		else
- 			use_defaults = false;
- 
- 		/* Ignore if it doesn't match requested argument count */
- 		if (nargs >= 0 && pronargs != nargs && !variadic && !use_defaults)
- 			continue;
  
  		if (OidIsValid(namespaceId))
  		{
--- 758,811 ----
  		int			pronargs = procform->pronargs;
  		int			effective_nargs;
  		int			pathpos = 0;
! 		bool		variadic = false;
! 		bool		use_defaults = false;
! 		Oid			va_elem_type = InvalidOid;
  		FuncCandidateList newResult;
+ 		short int	*param_map = NULL;
  
! 		if (argnames != NIL)
  		{
! 			if (!VerifyCandidateNamedNotation(proctup, pronargs, nargs, argnames, procform->pronargdefaults,
! 								    &use_defaults, &param_map))
! 				continue;
  		}
  		else
  		{
! 			/*
! 			* Check if function is variadic, and get variadic element type if so.
! 			 * If expand_variadic is false, we should just ignore variadic-ness.
! 			 */
! 			if (pronargs <= nargs && expand_variadic)
! 			{
! 				va_elem_type = procform->provariadic;
! 				variadic = OidIsValid(va_elem_type);
! 				any_special |= variadic;
! 			}
! 			else
! 			{
! 				va_elem_type = InvalidOid;
! 				variadic = false;
! 			}
  
! 			/*
! 			 * Check if function can match by using parameter defaults.
! 			 */
! 			if (pronargs > nargs && expand_defaults)
! 			{
! 				/* Ignore if not enough default expressions */
! 				if (nargs + procform->pronargdefaults < pronargs)
! 					continue;
! 				use_defaults = true;
! 				any_special = true;
! 			}
! 			else
! 				use_defaults = false;
! 
! 			/* Ignore if it doesn't match requested argument count */
! 			if (nargs >= 0 && pronargs != nargs && !variadic && !use_defaults)
  				continue;
  		}
  
  		if (OidIsValid(namespaceId))
  		{
*************** FuncnameGetCandidates(List *names, int n
*** 722,727 ****
--- 845,851 ----
  		newResult->pathpos = pathpos;
  		newResult->oid = HeapTupleGetOid(proctup);
  		newResult->nargs = effective_nargs;
+ 		newResult->param_map = param_map;
  		memcpy(newResult->args, procform->proargtypes.values,
  			   pronargs * sizeof(Oid));
  		if (variadic)
*************** FuncnameGetCandidates(List *names, int n
*** 735,741 ****
  		}
  		else
  			newResult->nvargs = 0;
! 		newResult->ndargs = use_defaults ? pronargs - nargs : 0;
  
  		/*
  		 * Does it have the same arguments as something we already accepted?
--- 859,872 ----
  		}
  		else
  			newResult->nvargs = 0;
! 		/* When named notation is used, then complete set of defaults is returned */
! 		if (argnames != NIL)
! 		{
! 			Assert(param_map != NULL);
! 			newResult->ndargs = procform->pronargdefaults;
! 		}
! 		else
! 			newResult->ndargs = use_defaults ? pronargs - nargs : 0;
  
  		/*
  		 * Does it have the same arguments as something we already accepted?
*************** FunctionIsVisible(Oid funcid)
*** 932,938 ****
  		visible = false;
  
  		clist = FuncnameGetCandidates(list_make1(makeString(proname)),
! 									  nargs, false, false);
  
  		for (; clist; clist = clist->next)
  		{
--- 1063,1069 ----
  		visible = false;
  
  		clist = FuncnameGetCandidates(list_make1(makeString(proname)),
! 									  nargs, NIL, false, false);
  
  		for (; clist; clist = clist->next)
  		{
*************** FunctionIsVisible(Oid funcid)
*** 953,959 ****
  
  
  /*
!  * OpernameGetOprid
   *		Given a possibly-qualified operator name and exact input datatypes,
   *		look up the operator.  Returns InvalidOid if not found.
   *
--- 1084,1090 ----
  
  
  /*
!  * OpernameGetOpri
   *		Given a possibly-qualified operator name and exact input datatypes,
   *		look up the operator.  Returns InvalidOid if not found.
   *
diff --git a/src/backend/catalog/pg_aggregate.c b/src/backend/catalog/pg_aggregate.c
index 845322e..26651d5 100644
*** a/src/backend/catalog/pg_aggregate.c
--- b/src/backend/catalog/pg_aggregate.c
*************** lookup_agg_function(List *fnName,
*** 321,329 ****
  	 * function's return value.  it also returns the true argument types to
  	 * the function.
  	 */
! 	fdresult = func_get_detail(fnName, 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))
--- 321,329 ----
  	 * function's return value.  it also returns the true argument types to
  	 * the function.
  	 */
! 	fdresult = func_get_detail(fnName, NIL, NIL, nargs, input_types, false, false,
  							   &fnOid, rettype, &retset, &nvargs,
! 							   &true_oid_array, NULL, NULL, NULL);
  
  	/* only valid case is a normal function not returning a set */
  	if (fdresult != FUNCDETAIL_NORMAL || !OidIsValid(fnOid))
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 1976648..89e506b 100644
*** a/src/backend/nodes/copyfuncs.c
--- b/src/backend/nodes/copyfuncs.c
*************** _copyFuncExpr(FuncExpr *from)
*** 1013,1018 ****
--- 1013,1019 ----
  	COPY_SCALAR_FIELD(funcresulttype);
  	COPY_SCALAR_FIELD(funcretset);
  	COPY_SCALAR_FIELD(funcformat);
+ 	COPY_SCALAR_FIELD(argformat);
  	COPY_NODE_FIELD(args);
  	COPY_LOCATION_FIELD(location);
  
*************** _copyFuncCall(FuncCall *from)
*** 1913,1918 ****
--- 1914,1930 ----
  	return newnode;
  }
  
+ static ArgExpr *
+ _copyArgExpr(ArgExpr *from)
+ {
+ 	ArgExpr *newnode = makeNode(ArgExpr);
+
+ 	COPY_STRING_FIELD(name);
+ 	COPY_NODE_FIELD(expr);
+
+ 	return newnode;
+ }
+ 
  static A_Star *
  _copyAStar(A_Star *from)
  {
*************** copyObject(void *from)
*** 4012,4017 ****
--- 4024,4032 ----
  		case T_FuncCall:
  			retval = _copyFuncCall(from);
  			break;
+ 		case T_ArgExpr:
+ 			retval = _copyArgExpr(from);
+ 			break;
  		case T_A_Star:
  			retval = _copyAStar(from);
  			break;
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 8b466f4..ee7f7f8 100644
*** a/src/backend/nodes/equalfuncs.c
--- b/src/backend/nodes/equalfuncs.c
*************** _equalFuncExpr(FuncExpr *a, FuncExpr *b)
*** 235,240 ****
--- 235,241 ----
  		b->funcformat != COERCE_DONTCARE)
  		return false;
  
+ 	COMPARE_SCALAR_FIELD(argformat);
  	COMPARE_NODE_FIELD(args);
  	COMPARE_LOCATION_FIELD(location);
  
diff --git a/src/backend/nodes/makefuncs.c b/src/backend/nodes/makefuncs.c
index 9ed9018..de816b6 100644
*** a/src/backend/nodes/makefuncs.c
--- b/src/backend/nodes/makefuncs.c
*************** makeFuncExpr(Oid funcid, Oid rettype, Li
*** 342,347 ****
--- 342,348 ----
  	funcexpr->funcresulttype = rettype;
  	funcexpr->funcretset = false;		/* only allowed case here */
  	funcexpr->funcformat = fformat;
+ 	funcexpr->argformat = CONTINUOUS_LIST;
  	funcexpr->args = args;
  	funcexpr->location = -1;
  
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 6030292..9f178b7 100644
*** a/src/backend/nodes/outfuncs.c
--- b/src/backend/nodes/outfuncs.c
*************** _outFuncExpr(StringInfo str, FuncExpr *n
*** 871,876 ****
--- 871,877 ----
  	WRITE_OID_FIELD(funcresulttype);
  	WRITE_BOOL_FIELD(funcretset);
  	WRITE_ENUM_FIELD(funcformat, CoercionForm);
+ 	WRITE_ENUM_FIELD(argformat, ArgumentForm);
  	WRITE_NODE_FIELD(args);
  	WRITE_LOCATION_FIELD(location);
  }
*************** _outFuncCall(StringInfo str, FuncCall *n
*** 1795,1800 ****
--- 1796,1810 ----
  }
  
  static void
+ _outArgExpr(StringInfo str, ArgExpr *node)
+ {
+ 	WRITE_NODE_TYPE("ARGEXPR");
+
+ 	WRITE_STRING_FIELD(name);
+ 	WRITE_NODE_FIELD(expr);
+ }
+ 
+ static void
  _outDefElem(StringInfo str, DefElem *node)
  {
  	WRITE_NODE_TYPE("DEFELEM");
*************** _outNode(StringInfo str, void *obj)
*** 2765,2770 ****
--- 2775,2783 ----
  			case T_FuncCall:
  				_outFuncCall(str, obj);
  				break;
+ 			case T_ArgExpr:
+ 				_outArgExpr(str, obj);
+ 				break;
  			case T_DefElem:
  				_outDefElem(str, obj);
  				break;
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index 4f7b740..71cca3e 100644
*** a/src/backend/nodes/readfuncs.c
--- b/src/backend/nodes/readfuncs.c
*************** _readFuncExpr(void)
*** 519,524 ****
--- 519,525 ----
  	READ_OID_FIELD(funcresulttype);
  	READ_BOOL_FIELD(funcretset);
  	READ_ENUM_FIELD(funcformat, CoercionForm);
+ 	READ_ENUM_FIELD(argformat, ArgumentForm);
  	READ_NODE_FIELD(args);
  	READ_LOCATION_FIELD(location);
  
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index be75590..5dcabf4 100644
*** a/src/backend/optimizer/util/clauses.c
--- b/src/backend/optimizer/util/clauses.c
*************** static List *simplify_and_arguments(List
*** 95,105 ****
  static Expr *simplify_boolean_equality(List *args);
  static Expr *simplify_function(Oid funcid,
  				  Oid result_type, int32 result_typmod, List **args,
! 				  bool allow_inline,
  				  eval_const_expressions_context *context);
! static List *add_function_defaults(List *args, Oid result_type,
! 					  HeapTuple func_tuple,
! 					  eval_const_expressions_context *context);
  static Expr *evaluate_function(Oid funcid,
  				  Oid result_type, int32 result_typmod, List *args,
  				  HeapTuple func_tuple,
--- 95,107 ----
  static Expr *simplify_boolean_equality(List *args);
  static Expr *simplify_function(Oid funcid,
  				  Oid result_type, int32 result_typmod, List **args,
! 				  bool leaky_list, bool allow_inline,
  				  eval_const_expressions_context *context);
! static List *add_function_defaults(List *args,
! 								   bool leaky_list,
! 								   Oid result_type,
! 								   HeapTuple func_tuple,
! 								   eval_const_expressions_context *context);
  static Expr *evaluate_function(Oid funcid,
  				  Oid result_type, int32 result_typmod, List *args,
  				  HeapTuple func_tuple,
*************** eval_const_expressions_mutator(Node *nod
*** 2133,2139 ****
  		 */
  		simple = simplify_function(expr->funcid,
  								   expr->funcresulttype, exprTypmod(node),
! 								   &args,
  								   true, context);
  		if (simple)				/* successfully simplified it */
  			return (Node *) simple;
--- 2135,2141 ----
  		 */
  		simple = simplify_function(expr->funcid,
  								   expr->funcresulttype, exprTypmod(node),
! 								   &args, expr->argformat == LEAKY_LIST,
  								   true, context);
  		if (simple)				/* successfully simplified it */
  			return (Node *) simple;
*************** eval_const_expressions_mutator(Node *nod
*** 2148,2153 ****
--- 2150,2156 ----
  		newexpr->funcresulttype = expr->funcresulttype;
  		newexpr->funcretset = expr->funcretset;
  		newexpr->funcformat = expr->funcformat;
+ 		newexpr->argformat = expr->argformat;
  		newexpr->args = args;
  		newexpr->location = expr->location;
  		return (Node *) newexpr;
*************** eval_const_expressions_mutator(Node *nod
*** 2180,2186 ****
  		 */
  		simple = simplify_function(expr->opfuncid,
  								   expr->opresulttype, -1,
! 								   &args,
  								   true, context);
  		if (simple)				/* successfully simplified it */
  			return (Node *) simple;
--- 2183,2189 ----
  		 */
  		simple = simplify_function(expr->opfuncid,
  								   expr->opresulttype, -1,
! 								   &args, false,
  								   true, context);
  		if (simple)				/* successfully simplified it */
  			return (Node *) simple;
*************** eval_const_expressions_mutator(Node *nod
*** 2271,2277 ****
  			 */
  			simple = simplify_function(expr->opfuncid,
  									   expr->opresulttype, -1,
! 									   &args,
  									   false, context);
  			if (simple)			/* successfully simplified it */
  			{
--- 2274,2280 ----
  			 */
  			simple = simplify_function(expr->opfuncid,
  									   expr->opresulttype, -1,
! 									   &args, false,
  									   false, context);
  			if (simple)			/* successfully simplified it */
  			{
*************** eval_const_expressions_mutator(Node *nod
*** 2463,2469 ****
  
  		simple = simplify_function(outfunc,
  								   CSTRINGOID, -1,
! 								   &args,
  								   true, context);
  		if (simple)				/* successfully simplified output fn */
  		{
--- 2466,2472 ----
  
  		simple = simplify_function(outfunc,
  								   CSTRINGOID, -1,
! 								   &args, false,
  								   true, context);
  		if (simple)				/* successfully simplified output fn */
  		{
*************** eval_const_expressions_mutator(Node *nod
*** 2481,2487 ****
  
  			simple = simplify_function(infunc,
  									   expr->resulttype, -1,
! 									   &args,
  									   true, context);
  			if (simple)			/* successfully simplified input fn */
  				return (Node *) simple;
--- 2484,2490 ----
  
  			simple = simplify_function(infunc,
  									   expr->resulttype, -1,
! 									   &args, false,
  									   true, context);
  			if (simple)			/* successfully simplified input fn */
  				return (Node *) simple;
*************** simplify_boolean_equality(List *args)
*** 3226,3231 ****
--- 3229,3235 ----
  static Expr *
  simplify_function(Oid funcid, Oid result_type, int32 result_typmod,
  				  List **args,
+ 				  bool leaky_list,
  				  bool allow_inline,
  				  eval_const_expressions_context *context)
  {
*************** simplify_function(Oid funcid, Oid result
*** 3247,3254 ****
  		elog(ERROR, "cache lookup failed for function %u", funcid);
  
  	/* While we have the tuple, check if we need to add defaults */
! 	if (((Form_pg_proc) GETSTRUCT(func_tuple))->pronargs > list_length(*args))
! 		*args = add_function_defaults(*args, result_type, func_tuple, context);
  
  	newexpr = evaluate_function(funcid, result_type, result_typmod, *args,
  								func_tuple, context);
--- 3251,3258 ----
  		elog(ERROR, "cache lookup failed for function %u", funcid);
  
  	/* While we have the tuple, check if we need to add defaults */
! 	if (((Form_pg_proc) GETSTRUCT(func_tuple))->pronargs > list_length(*args) || leaky_list)
! 		*args = add_function_defaults(*args, leaky_list, result_type, func_tuple, context);
  
  	newexpr = evaluate_function(funcid, result_type, result_typmod, *args,
  								func_tuple, context);
*************** simplify_function(Oid funcid, Oid result
*** 3271,3277 ****
   * just like the parser did.
   */
  static List *
! add_function_defaults(List *args, Oid result_type, HeapTuple func_tuple,
  					  eval_const_expressions_context *context)
  {
  	Form_pg_proc funcform = (Form_pg_proc) GETSTRUCT(func_tuple);
--- 3275,3281 ----
   * just like the parser did.
   */
  static List *
! add_function_defaults(List *args, bool leaky_list, Oid result_type, HeapTuple func_tuple,
  					  eval_const_expressions_context *context)
  {
  	Form_pg_proc funcform = (Form_pg_proc) GETSTRUCT(func_tuple);
*************** add_function_defaults(List *args, Oid re
*** 3297,3310 ****
  	defaults = (List *) stringToNode(str);
  	Assert(IsA(defaults, List));
  	pfree(str);
! 	/* Delete any unused defaults from the list */
! 	ndelete = nargsprovided + list_length(defaults) - funcform->pronargs;
! 	if (ndelete < 0)
! 		elog(ERROR, "not enough default arguments");
! 	while (ndelete-- > 0)
! 		defaults = list_delete_first(defaults);
! 	/* And form the combined argument list */
! 	args = list_concat(args, defaults);
  	Assert(list_length(args) == funcform->pronargs);
  
  	/*
--- 3301,3341 ----
  	defaults = (List *) stringToNode(str);
  	Assert(IsA(defaults, List));
  	pfree(str);
!
! 	if (leaky_list)
! 	{
! 		List	*cargs = NIL;			/* continuous argument list */
! 		ListCell	*lc;
! 		int		i = 0;
! 		bool		first_default = funcform->pronargs - funcform->pronargdefaults;
!
! 		/* Replace gaps with elements from defaults */
! 		foreach(lc, args)
! 		{
! 			Node *arg = (Node *) lfirst(lc);
!
! 			if (arg == NULL)
! 			{
! 				Assert(i >= first_default);
! 				cargs = lappend(cargs, list_nth(defaults, i - first_default));
! 			}
! 			else
! 				cargs = lappend(cargs, arg);
! 			i++;
! 		}
! 		args = cargs;
! 	}
! 	else
! 	{
! 		/* Delete any unused defaults from the list */
! 		ndelete = nargsprovided + list_length(defaults) - funcform->pronargs;
! 		if (ndelete < 0)
! 			elog(ERROR, "not enough default arguments");
! 		while (ndelete-- > 0)
! 			defaults = list_delete_first(defaults);
! 		/* And form the combined argument list */
! 		args = list_concat(args, defaults);
! 	}
  	Assert(list_length(args) == funcform->pronargs);
  
  	/*
*************** evaluate_function(Oid funcid, Oid result
*** 3443,3448 ****
--- 3474,3480 ----
  	newexpr->funcresulttype = result_type;
  	newexpr->funcretset = false;
  	newexpr->funcformat = COERCE_DONTCARE;		/* doesn't matter */
+ 	newexpr->funcformat = CONTINUOUS_LIST;
  	newexpr->args = args;
  	newexpr->location = -1;
  
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 858e16c..ddfe95d 100644
*** a/src/backend/parser/gram.y
--- b/src/backend/parser/gram.y
*************** static TypeName *TableFuncTypeName(List 
*** 419,424 ****
--- 419,427 ----
  %type <str>		opt_existing_window_name
  %type <ival>	opt_frame_clause frame_extent frame_bound
  
+ %type <list>	arg_expr_list
+ %type <node>	arg_expr
+ 
  
  /*
   * Non-keyword token types.  These are hard-wired into the "flex" lexer.
*************** func_expr:	func_name '(' ')' over_clause
*** 8794,8800 ****
  					n->location = @1;
  					$$ = (Node *)n;
  				}
! 			| func_name '(' expr_list ')' over_clause
  				{
  					FuncCall *n = makeNode(FuncCall);
  					n->funcname = $1;
--- 8797,8803 ----
  					n->location = @1;
  					$$ = (Node *)n;
  				}
! 			| func_name '(' arg_expr_list ')' over_clause
  				{
  					FuncCall *n = makeNode(FuncCall);
  					n->funcname = $1;
*************** func_expr:	func_name '(' ')' over_clause
*** 8818,8824 ****
  					n->location = @1;
  					$$ = (Node *)n;
  				}
! 			| func_name '(' expr_list ',' VARIADIC a_expr ')' over_clause
  				{
  					FuncCall *n = makeNode(FuncCall);
  					n->funcname = $1;
--- 8821,8827 ----
  					n->location = @1;
  					$$ = (Node *)n;
  				}
! 			| func_name '(' arg_expr_list ',' VARIADIC a_expr ')' over_clause
  				{
  					FuncCall *n = makeNode(FuncCall);
  					n->funcname = $1;
*************** func_expr:	func_name '(' ')' over_clause
*** 8830,8836 ****
  					n->location = @1;
  					$$ = (Node *)n;
  				}
! 			| func_name '(' ALL expr_list ')' over_clause
  				{
  					FuncCall *n = makeNode(FuncCall);
  					n->funcname = $1;
--- 8833,8839 ----
  					n->location = @1;
  					$$ = (Node *)n;
  				}
! 			| func_name '(' ALL arg_expr_list ')' over_clause
  				{
  					FuncCall *n = makeNode(FuncCall);
  					n->funcname = $1;
*************** func_expr:	func_name '(' ')' over_clause
*** 8846,8852 ****
  					n->location = @1;
  					$$ = (Node *)n;
  				}
! 			| func_name '(' DISTINCT expr_list ')' over_clause
  				{
  					FuncCall *n = makeNode(FuncCall);
  					n->funcname = $1;
--- 8849,8855 ----
  					n->location = @1;
  					$$ = (Node *)n;
  				}
! 			| func_name '(' DISTINCT arg_expr_list ')' over_clause
  				{
  					FuncCall *n = makeNode(FuncCall);
  					n->funcname = $1;
*************** expr_list:	a_expr
*** 9568,9573 ****
--- 9571,9601 ----
  					$$ = lappend($1, $3);
  				}
  		;
+
+ /*  Used for support of named notation.
+  */
+ arg_expr_list: arg_expr
+ 				{
+ 					$$ = list_make1($1);
+ 				}
+ 			| arg_expr_list ',' arg_expr
+ 				{
+ 					$$ = lappend($1, $3);
+ 				}
+ 		;
+
+ arg_expr:	a_expr
+ 				{
+ 					$$ = $1;
+ 				}
+ 			| a_expr AS param_name
+ 				{
+ 					ArgExpr *ae = makeNode(ArgExpr); 
+ 					ae->expr = $1;
+ 					ae->name = $3;
+ 					$$ = (Node *) ae;
+ 				}
+ 		; 
  
  type_list:	Typename								{ $$ = list_make1($1); }
  			| type_list ',' Typename				{ $$ = lappend($1, $3); }
*************** name_list:	name
*** 9968,9974 ****
  		;
  
  
! name:		ColId									{ $$ = $1; };
  
  database_name:
  			ColId									{ $$ = $1; };
--- 9996,10002 ----
  		;
  
  
! name:		ColId								{ $$ = $1; };
  
  database_name:
  			ColId									{ $$ = $1; };
*************** func_name:	type_function_name
*** 10001,10007 ****
  
  
  /*
!  * Constants
   */
  AexprConst: Iconst
  				{
--- 10029,10035 ----
  
  
  /*
!  * Constants ToDo - PStehule
   */
  AexprConst: Iconst
  				{
*************** AexprConst: Iconst
*** 10035,10044 ****
  					t->location = @1;
  					$$ = makeStringConstCast($2, @2, t);
  				}
! 			| func_name '(' expr_list ')' Sconst
  				{
  					/* generic syntax with a type modifier */
  					TypeName *t = makeTypeNameFromNameList($1);
  					t->typmods = $3;
  					t->location = @1;
  					$$ = makeStringConstCast($5, @5, t);
--- 10063,10080 ----
  					t->location = @1;
  					$$ = makeStringConstCast($2, @2, t);
  				}
! 			| func_name '(' arg_expr_list ')' Sconst
  				{
  					/* generic syntax with a type modifier */
  					TypeName *t = makeTypeNameFromNameList($1);
+ 					ListCell *lc;
+
+ 					/* Don't allow ArgExpr in this context */
+ 					foreach(lc, $3)
+ 					{
+ 						if (IsA((Node *) lfirst(lc),ArgExpr))
+ 							elog(ERROR, "don't use named parameters in this context");
+ 					}
  					t->typmods = $3;
  					t->location = @1;
  					$$ = makeStringConstCast($5, @5, t);
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index 428adbd..8ad5a2c 100644
*** a/src/backend/parser/parse_expr.c
--- b/src/backend/parser/parse_expr.c
*************** transformIndirection(ParseState *pstate,
*** 362,368 ****
  									   list_make1(n),
  									   list_make1(result),
  									   false, false, false,
! 									   NULL, true, -1);
  		}
  	}
  	/* process trailing subscripts, if any */
--- 362,368 ----
  									   list_make1(n),
  									   list_make1(result),
  									   false, false, false,
! 									   NULL, true, NIL, -1);
  		}
  	}
  	/* process trailing subscripts, if any */
*************** transformColumnRef(ParseState *pstate, C
*** 506,512 ****
  											 list_make1(makeString(name2)),
  											 list_make1(node),
  											 false, false, false,
! 											 NULL, true, cref->location);
  				}
  				break;
  			}
--- 506,512 ----
  											 list_make1(makeString(name2)),
  											 list_make1(node),
  											 false, false, false,
! 											 NULL, true, NIL, cref->location);
  				}
  				break;
  			}
*************** transformColumnRef(ParseState *pstate, C
*** 547,553 ****
  											 list_make1(makeString(name3)),
  											 list_make1(node),
  											 false, false, false,
! 											 NULL, true, cref->location);
  				}
  				break;
  			}
--- 547,553 ----
  											 list_make1(makeString(name3)),
  											 list_make1(node),
  											 false, false, false,
! 											 NULL, true, NIL, cref->location);
  				}
  				break;
  			}
*************** transformColumnRef(ParseState *pstate, C
*** 602,608 ****
  											 list_make1(makeString(name4)),
  											 list_make1(node),
  											 false, false, false,
! 											 NULL, true, cref->location);
  				}
  				break;
  			}
--- 602,608 ----
  											 list_make1(makeString(name4)),
  											 list_make1(node),
  											 false, false, false,
! 											 NULL, true, NIL, cref->location);
  				}
  				break;
  			}
*************** transformAExprIn(ParseState *pstate, A_E
*** 1091,1107 ****
  static Node *
  transformFuncCall(ParseState *pstate, FuncCall *fn)
  {
! 	List	   *targs;
  	ListCell   *args;
  
  	/* Transform the list of arguments ... */
- 	targs = NIL;
  	foreach(args, fn->args)
  	{
! 		targs = lappend(targs, transformExpr(pstate,
! 											 (Node *) lfirst(args)));
  	}
  
  	/* ... and hand off to ParseFuncOrColumn */
  	return ParseFuncOrColumn(pstate,
  							 fn->funcname,
--- 1091,1158 ----
  static Node *
  transformFuncCall(ParseState *pstate, FuncCall *fn)
  {
! 	List	   *targs = NIL;
  	ListCell   *args;
+ 	List		*argnames = NIL;
+ 	bool		argnames_used = false;
+ 	FuncCallNotation	notation = POSITIONAL_NOTATION;
  
  	/* Transform the list of arguments ... */
  	foreach(args, fn->args)
  	{
! 		char	*name = NULL;
! 		Node	*targ = NULL;
! 		Node		*arg = lfirst(args);
!
! 		if (IsA(arg, ArgExpr))
! 		{
! 			ArgExpr    *argexpr = (ArgExpr *) arg;
! 			ListCell	*lc;
!
! 			Assert(argexpr->name != NULL);
!
! 			argnames_used = true;
! 			notation = NAMED_NOTATION;
!
! 			name = argexpr->name;
! 			targ = transformExpr(pstate, argexpr->expr);
! 
! 			/* Check duplicates */
! 			for_each_cell(lc, lnext(args))
! 			{
! 				if (IsA(lfirst(lc), ArgExpr))
! 				{
! 					char *next_name = ((ArgExpr *) lfirst(lc))->name;
!
! 					Assert(next_name != NULL);
! 					if (strcmp(name, next_name) == 0)
! 						ereport(ERROR,
! 							(errcode(ERRCODE_SYNTAX_ERROR),
! 							 errmsg("function parameter \"%s\" is used more then once", name),
! 							 errhint("Check used names of next parameters."),
! 							 parser_errposition(pstate, exprLocation(targ))));
! 				}
! 			}
! 		}
! 		else
! 		{
! 			targ = transformExpr(pstate, arg);
! 			if (notation != POSITIONAL_NOTATION)
! 				ereport(ERROR,
! 						(errcode(ERRCODE_SYNTAX_ERROR),
! 						 errmsg("expected named expression"),
! 						 errhint("You can't put positionals arguments behind the named arguments."),
! 						 parser_errposition(pstate, exprLocation(targ))));
! 		}
!
! 		targs = lappend(targs, targ);
! 		argnames = lappend(argnames, name);
  	}
  
+ 	/* forgot list of NULLs */
+ 	if (!argnames_used)
+ 		argnames = NIL;
+ 
  	/* ... and hand off to ParseFuncOrColumn */
  	return ParseFuncOrColumn(pstate,
  							 fn->funcname,
*************** transformFuncCall(ParseState *pstate, Fu
*** 1111,1116 ****
--- 1162,1168 ----
  							 fn->func_variadic,
  							 fn->over,
  							 false,
+ 							 argnames,
  							 fn->location);
  }
  
*************** transformCaseExpr(ParseState *pstate, Ca
*** 1167,1173 ****
  		Node	   *warg;
  
  		Assert(IsA(w, CaseWhen));
- 
  		warg = (Node *) w->expr;
  		if (placeholder)
  		{
--- 1219,1224 ----
diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c
index 8ea76ab..556d4fe 100644
*** a/src/backend/parser/parse_func.c
--- b/src/backend/parser/parse_func.c
*************** static void unknown_attribute(ParseState
*** 59,65 ****
  Node *
  ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
  				  bool agg_star, bool agg_distinct, bool func_variadic,
! 				  WindowDef *over, bool is_column, int location)
  {
  	Oid			rettype;
  	Oid			funcid;
--- 59,65 ----
  Node *
  ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
  				  bool agg_star, bool agg_distinct, bool func_variadic,
! 				  WindowDef *over, bool is_column, List *argnames, int location)
  {
  	Oid			rettype;
  	Oid			funcid;
*************** ParseFuncOrColumn(ParseState *pstate, Li
*** 75,80 ****
--- 75,83 ----
  	bool		retset;
  	int			nvargs;
  	FuncDetailCode fdresult;
+ 	short int	*param_map;
+ 	int		pronargs;
+ 	ArgumentForm	argformat = CONTINUOUS_LIST;
  
  	/*
  	 * Most of the rest of the parser just assumes that functions do not have
*************** ParseFuncOrColumn(ParseState *pstate, Li
*** 130,136 ****
  	 * wasn't any aggregate or variadic decoration.
  	 */
  	if (nargs == 1 && !agg_star && !agg_distinct && over == NULL &&
! 		!func_variadic && list_length(funcname) == 1)
  	{
  		Oid			argtype = actual_arg_types[0];
  
--- 133,139 ----
  	 * wasn't any aggregate or variadic decoration.
  	 */
  	if (nargs == 1 && !agg_star && !agg_distinct && over == NULL &&
! 		!func_variadic && list_length(funcname) == 1 && argnames == NIL)
  	{
  		Oid			argtype = actual_arg_types[0];
  
*************** ParseFuncOrColumn(ParseState *pstate, Li
*** 161,170 ****
  	 * replaced by a suitable number of copies of its element type.  We'll fix
  	 * it up below.  We may also have to deal with default arguments.
  	 */
! 	fdresult = func_get_detail(funcname, fargs, nargs, actual_arg_types,
  							   !func_variadic, true,
  							   &funcid, &rettype, &retset, &nvargs,
! 							   &declared_arg_types, &argdefaults);
  	if (fdresult == FUNCDETAIL_COERCION)
  	{
  		/*
--- 164,173 ----
  	 * replaced by a suitable number of copies of its element type.  We'll fix
  	 * it up below.  We may also have to deal with default arguments.
  	 */
! 	fdresult = func_get_detail(funcname, fargs, argnames, nargs, actual_arg_types,
  							   !func_variadic, true,
  							   &funcid, &rettype, &retset, &nvargs,
! 							   &declared_arg_types, &argdefaults, &param_map, &pronargs);
  	if (fdresult == FUNCDETAIL_COERCION)
  	{
  		/*
*************** ParseFuncOrColumn(ParseState *pstate, Li
*** 241,269 ****
  					 parser_errposition(pstate, location)));
  	}
  
! 	/*
! 	 * If there are default arguments, we have to include their types in
! 	 * actual_arg_types for the purpose of checking generic type consistency.
! 	 * However, we do NOT put them into the generated parse node, because
! 	 * their actual values might change before the query gets run.	The
! 	 * planner has to insert the up-to-date values at plan time.
! 	 */
! 	nargsplusdefs = nargs;
! 	foreach(l, argdefaults)
  	{
! 		Node	   *expr = (Node *) lfirst(l);
! 
! 		/* probably shouldn't happen ... */
! 		if (nargsplusdefs >= FUNC_MAX_ARGS)
! 			ereport(ERROR,
! 					(errcode(ERRCODE_TOO_MANY_ARGUMENTS),
! 			 errmsg_plural("cannot pass more than %d argument to a function",
! 						   "cannot pass more than %d arguments to a function",
! 						   FUNC_MAX_ARGS,
! 						   FUNC_MAX_ARGS),
! 					 parser_errposition(pstate, location)));
! 
! 		actual_arg_types[nargsplusdefs++] = exprType(expr);
  	}
  
  	/*
--- 244,305 ----
  					 parser_errposition(pstate, location)));
  	}
  
!
! 	if (param_map != NULL)
  	{
! 		List	*rfargs = NIL;			/* reordered list of function arguments */
! 		int		i;
!
! 		for (i = 0; i < pronargs; i++)
! 		{
! 			Node	*expr = NULL;
!
! 			if (param_map[i] < nargs)
! 			{
! 				expr = (Node *) list_nth(fargs, param_map[i]);
! 				rfargs = lappend(rfargs, expr);
! 				/* when any arg goes out of narg */
! 				if (i >= nargs)
! 					argformat = LEAKY_LIST;
! 			}
! 			else
! 			{
! 				expr = (Node *) list_nth(argdefaults, param_map[i] - nargs);
! 				rfargs = lappend(rfargs, NULL);
! 			}
! 			actual_arg_types[i] = exprType(expr);
! 		}
!
! 		fargs = (argformat == LEAKY_LIST) ? rfargs : list_truncate(rfargs, nargs);
! 		nargsplusdefs = pronargs;
! 	}
! 	else
! 	{
! 		/*
! 		 * If there are default arguments, we have to include their types in
! 		 * actual_arg_types for the purpose of checking generic type consistency.
! 		 * However, we do NOT put them into the generated parse node, because
! 		 * their actual values might change before the query gets run.	The
! 		 * planner has to insert the up-to-date values at plan time.
! 		 */
!
! 		nargsplusdefs = nargs;
! 		foreach(l, argdefaults)
! 		{
! 			Node	   *expr = (Node *) lfirst(l);
!
! 			/* probably shouldn't happen ... */
! 			if (nargsplusdefs >= FUNC_MAX_ARGS)
! 				ereport(ERROR,
! 						(errcode(ERRCODE_TOO_MANY_ARGUMENTS),
! 						 errmsg_plural("cannot pass more than %d argument to a function",
! 									   "cannot pass more than %d arguments to a function",
! 									   FUNC_MAX_ARGS,
! 									   FUNC_MAX_ARGS),
! 						 parser_errposition(pstate, location)));
!
! 			actual_arg_types[nargsplusdefs++] = exprType(expr);
! 		}
  	}
  
  	/*
*************** ParseFuncOrColumn(ParseState *pstate, Li
*** 319,324 ****
--- 355,361 ----
  		funcexpr->funcresulttype = rettype;
  		funcexpr->funcretset = retset;
  		funcexpr->funcformat = COERCE_EXPLICIT_CALL;
+ 		funcexpr->argformat = argformat;
  		funcexpr->args = fargs;
  		funcexpr->location = location;
  
*************** func_select_candidate(int nargs,
*** 809,814 ****
--- 846,852 ----
  FuncDetailCode
  func_get_detail(List *funcname,
  				List *fargs,
+ 				List *argnames,
  				int nargs,
  				Oid *argtypes,
  				bool expand_variadic,
*************** func_get_detail(List *funcname,
*** 817,824 ****
  				Oid *rettype,	/* return value */
  				bool *retset,	/* return value */
  				int *nvargs,	/* return value */
! 				Oid **true_typeids,		/* return value */
! 				List **argdefaults)		/* optional return value */
  {
  	FuncCandidateList raw_candidates;
  	FuncCandidateList best_candidate;
--- 855,864 ----
  				Oid *rettype,	/* return value */
  				bool *retset,	/* return value */
  				int *nvargs,	/* return value */
! 				Oid **true_typeids,	   /* return value */
! 				List **argdefaults,    /* optional return value */
! 				short int **param_map, /* optional return value */
! 				int *pronargs)		   /* optional return value */
  {
  	FuncCandidateList raw_candidates;
  	FuncCandidateList best_candidate;
*************** func_get_detail(List *funcname,
*** 833,839 ****
  		*argdefaults = NIL;
  
  	/* Get list of possible candidates from namespace search */
! 	raw_candidates = FuncnameGetCandidates(funcname, nargs,
  										   expand_variadic, expand_defaults);
  
  	/*
--- 873,879 ----
  		*argdefaults = NIL;
  
  	/* Get list of possible candidates from namespace search */
! 	raw_candidates = FuncnameGetCandidates(funcname, nargs, argnames,
  										   expand_variadic, expand_defaults);
  
  	/*
*************** func_get_detail(List *funcname,
*** 987,992 ****
--- 1027,1040 ----
  		pform = (Form_pg_proc) GETSTRUCT(ftup);
  		*rettype = pform->prorettype;
  		*retset = pform->proretset;
+
+ 		if (param_map)
+ 		{
+ 			Assert(pronargs != NULL);
+ 			*pronargs = best_candidate->nargs;
+ 			*param_map = best_candidate->param_map;
+ 		}
+
  		/* fetch default args if caller wants 'em */
  		if (argdefaults)
  		{
*************** make_fn_arguments(ParseState *pstate,
*** 1060,1065 ****
--- 1108,1115 ----
  		/* types don't match? then force coercion using a function call... */
  		if (actual_arg_types[i] != declared_arg_types[i])
  		{
+ 			Assert(lfirst(current_fargs) != NULL);
+
  			lfirst(current_fargs) = coerce_type(pstate,
  												lfirst(current_fargs),
  												actual_arg_types[i],
*************** LookupFuncName(List *funcname, int nargs
*** 1276,1282 ****
  {
  	FuncCandidateList clist;
  
! 	clist = FuncnameGetCandidates(funcname, nargs, false, false);
  
  	while (clist)
  	{
--- 1326,1332 ----
  {
  	FuncCandidateList clist;
  
! 	clist = FuncnameGetCandidates(funcname, nargs, NIL, false, false);
  
  	while (clist)
  	{
diff --git a/src/backend/utils/adt/regproc.c b/src/backend/utils/adt/regproc.c
index 0817e6a..dc58062 100644
*** a/src/backend/utils/adt/regproc.c
--- b/src/backend/utils/adt/regproc.c
*************** regprocin(PG_FUNCTION_ARGS)
*** 131,137 ****
  	 * pg_proc entries in the current search path.
  	 */
  	names = stringToQualifiedNameList(pro_name_or_oid);
! 	clist = FuncnameGetCandidates(names, -1, false, false);
  
  	if (clist == NULL)
  		ereport(ERROR,
--- 131,137 ----
  	 * pg_proc entries in the current search path.
  	 */
  	names = stringToQualifiedNameList(pro_name_or_oid);
! 	clist = FuncnameGetCandidates(names, -1, NIL, false, false);
  
  	if (clist == NULL)
  		ereport(ERROR,
*************** regprocout(PG_FUNCTION_ARGS)
*** 190,196 ****
  			 * qualify it.
  			 */
  			clist = FuncnameGetCandidates(list_make1(makeString(proname)),
! 										  -1, false, false);
  			if (clist != NULL && clist->next == NULL &&
  				clist->oid == proid)
  				nspname = NULL;
--- 190,196 ----
  			 * qualify it.
  			 */
  			clist = FuncnameGetCandidates(list_make1(makeString(proname)),
! 										  -1, NIL, false, false);
  			if (clist != NULL && clist->next == NULL &&
  				clist->oid == proid)
  				nspname = NULL;
*************** regprocedurein(PG_FUNCTION_ARGS)
*** 277,283 ****
  	 */
  	parseNameAndArgTypes(pro_name_or_oid, false, &names, &nargs, argtypes);
  
! 	clist = FuncnameGetCandidates(names, nargs, false, false);
  
  	for (; clist; clist = clist->next)
  	{
--- 277,283 ----
  	 */
  	parseNameAndArgTypes(pro_name_or_oid, false, &names, &nargs, argtypes);
  
! 	clist = FuncnameGetCandidates(names, nargs, NIL, false, false);
  
  	for (; clist; clist = clist->next)
  	{
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 333cb25..d5877a5 100644
*** a/src/backend/utils/adt/ruleutils.c
--- b/src/backend/utils/adt/ruleutils.c
*************** generate_function_name(Oid funcid, int n
*** 6372,6380 ****
  	 * specified argtypes.
  	 */
  	p_result = func_get_detail(list_make1(makeString(proname)),
! 							   NIL, nargs, argtypes, false, 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) &&
--- 6372,6380 ----
  	 * specified argtypes.
  	 */
  	p_result = func_get_detail(list_make1(makeString(proname)),
! 							   NIL, NIL, nargs, argtypes, false, true,
  							   &p_funcid, &p_rettype,
! 							   &p_retset, &p_nvargs, &p_true_typeids, NULL, NULL, NULL);
  	if ((p_result == FUNCDETAIL_NORMAL ||
  		 p_result == FUNCDETAIL_AGGREGATE ||
  		 p_result == FUNCDETAIL_WINDOWFUNC) &&
diff --git a/src/include/catalog/namespace.h b/src/include/catalog/namespace.h
index 956069d..a1cb70d 100644
*** a/src/include/catalog/namespace.h
--- b/src/include/catalog/namespace.h
*************** typedef struct _FuncCandidateList
*** 32,37 ****
--- 32,38 ----
  	int			nargs;			/* number of arg types returned */
  	int			nvargs;			/* number of args to become variadic array */
  	int			ndargs;			/* number of defaulted args */
+ 	short int		*param_map;		/* maps external arguments to function arguments */
  	Oid			args[1];		/* arg types --- VARIABLE LENGTH ARRAY */
  }	*FuncCandidateList;	/* VARIABLE LENGTH STRUCT */
  
*************** extern Oid	TypenameGetTypid(const char *
*** 55,62 ****
  extern bool TypeIsVisible(Oid typid);
  
  extern FuncCandidateList FuncnameGetCandidates(List *names, int nargs,
! 					  bool expand_variadic,
! 					  bool expand_defaults);
  extern bool FunctionIsVisible(Oid funcid);
  
  extern Oid	OpernameGetOprid(List *names, Oid oprleft, Oid oprright);
--- 56,64 ----
  extern bool TypeIsVisible(Oid typid);
  
  extern FuncCandidateList FuncnameGetCandidates(List *names, int nargs,
! 											   List *argnames,
! 											   bool expand_variadic,
! 											   bool expand_defaults);
  extern bool FunctionIsVisible(Oid funcid);
  
  extern Oid	OpernameGetOprid(List *names, Oid oprleft, Oid oprright);
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index 925375b..ff7f799 100644
*** a/src/include/nodes/nodes.h
--- b/src/include/nodes/nodes.h
*************** typedef enum NodeTag
*** 376,381 ****
--- 376,382 ----
  	T_XmlSerialize,
  	T_WithClause,
  	T_CommonTableExpr,
+ 	T_ArgExpr,
  
  	/*
  	 * TAGS FOR RANDOM OTHER STUFF
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 9d53ab9..84e91e0 100644
*** a/src/include/nodes/parsenodes.h
--- b/src/include/nodes/parsenodes.h
*************** typedef struct FuncCall
*** 282,287 ****
--- 282,305 ----
  } FuncCall;
  
  /*
+  * ArgExpr - an argument of function
+  */
+ typedef struct ArgExpr
+ {
+ 	NodeTag		type;
+ 	char	   *name;		/* an name of argument (when is specified) */
+ 	Node	   *expr;		/* the argument */
+ } ArgExpr;
+ 
+ 
+ /* notation used for Func call params */
+ typedef enum FuncCallNotation
+ {
+ 	POSITIONAL_NOTATION,
+ 	NAMED_NOTATION
+ } FuncCallNotation;
+ 
+ /*
   * A_Star - '*' representing all columns of a table or compound field
   *
   * This can appear within ColumnRef.fields, A_Indirection.indirection, and
diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h
index 6e7f52b..a1bdf0d 100644
*** a/src/include/nodes/primnodes.h
--- b/src/include/nodes/primnodes.h
*************** typedef enum CoercionForm
*** 299,304 ****
--- 299,310 ----
  	COERCE_DONTCARE				/* special case for planner */
  } CoercionForm;
  
+ typedef enum ArgumentForm
+ {
+ 	CONTINUOUS_LIST,		/* used for positional notation */
+ 	LEAKY_LIST			/* used for named and mixed notation */
+ } ArgumentForm;
+ 
  /*
   * FuncExpr - expression node for a function call
   */
*************** typedef struct FuncExpr
*** 309,314 ****
--- 315,321 ----
  	Oid			funcresulttype; /* PG_TYPE OID of result value */
  	bool		funcretset;		/* true if function returns set */
  	CoercionForm funcformat;	/* how to display this function call */
+ 	ArgumentForm argformat;		/* what is format of argument list */
  	List	   *args;			/* arguments to the function */
  	int			location;		/* token location, or -1 if unknown */
  } FuncExpr;
diff --git a/src/include/parser/parse_func.h b/src/include/parser/parse_func.h
index 2a49f00..940ed28 100644
*** a/src/include/parser/parse_func.h
--- b/src/include/parser/parse_func.h
*************** typedef enum
*** 45,58 ****
  extern Node *ParseFuncOrColumn(ParseState *pstate,
  				  List *funcname, List *fargs,
  				  bool agg_star, bool agg_distinct, bool func_variadic,
! 				  WindowDef *over, bool is_column, int location);
  
! extern FuncDetailCode func_get_detail(List *funcname, List *fargs,
! 				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,
--- 45,58 ----
  extern Node *ParseFuncOrColumn(ParseState *pstate,
  				  List *funcname, List *fargs,
  				  bool agg_star, bool agg_distinct, bool func_variadic,
! 				  WindowDef *over, bool is_column, List *argnames, int location);
  
! extern FuncDetailCode func_get_detail(List *funcname, List *fargs, List *argnames,
! 				int nargs, Oid *argtypes, 
  				bool expand_variadic, bool expand_defaults,
  				Oid *funcid, Oid *rettype,
  				bool *retset, int *nvargs, Oid **true_typeids,
! 				List **argdefaults, short int **param_map, int *pronargs);
  
  extern int func_match_argtypes(int nargs,
  					Oid *input_typeids,
diff --git a/src/test/regress/expected/polymorphism.out b/src/test/regress/expected/polymorphism.out
index 77f693c..9c60aaa 100644
*** a/src/test/regress/expected/polymorphism.out
--- b/src/test/regress/expected/polymorphism.out
*************** select dfunc('Hi');
*** 1038,1040 ****
--- 1038,1104 ----
  drop function dfunc(int, int, int);
  drop function dfunc(int, int);
  drop function dfunc(text);
+ -- test function with named params and using named or mixed notation
+ -- fail, unnamed param behind named
+ create function dfunc(a int, b int = 1, c int) returns table (a int, b int, c int) as $$
+   select $1, $2, $3;
+ $$ language sql;
+ ERROR:  input parameters after one with a default value must also have defaults
+ create function dfunc(a int, b int, c int=0, d int = 0) returns table (a int, b int, c int, d int) as $$
+   select $1, $2, $3, $4;
+ $$ language sql;
+ select (dfunc(10,20,30)).*;
+  a  | b  | c  | d 
+ ----+----+----+---
+  10 | 20 | 30 | 0
+ (1 row)
+ 
+ select (dfunc(10 as a, 20 as b, 30 as c)).*;
+  a  | b  | c  | d 
+ ----+----+----+---
+  10 | 20 | 30 | 0
+ (1 row)
+ 
+ select * from dfunc(10 as a, 20 as b);
+  a  | b  | c | d 
+ ----+----+---+---
+  10 | 20 | 0 | 0
+ (1 row)
+ 
+ select * from dfunc(10 as b, 20 as a);
+  a  | b  | c | d 
+ ----+----+---+---
+  20 | 10 | 0 | 0
+ (1 row)
+ 
+ select * from dfunc(0,0);
+  a | b | c | d 
+ ---+---+---+---
+  0 | 0 | 0 | 0
+ (1 row)
+ 
+ select * from dfunc(0,0,10 as c);
+  a | b | c  | d 
+ ---+---+----+---
+  0 | 0 | 10 | 0
+ (1 row)
+ 
+ select * from dfunc(0,0,10 as d);
+  a | b | c | d  
+ ---+---+---+----
+  0 | 0 | 0 | 10
+ (1 row)
+ 
+ select * from dfunc(10 as x, 20 as b, 30 as c); --fail - unknown param
+ ERROR:  function dfunc(integer, integer, integer) does not exist
+ LINE 1: select * from dfunc(10 as x, 20 as b, 30 as c);
+                       ^
+ HINT:  No function matches the given name and argument types. You might need to add explicit type casts.
+ select * from dfunc(10, 20 as b, 30); -- fail using positional notation begind named notation
+ ERROR:  expected named expression
+ LINE 1: select * from dfunc(10, 20 as b, 30);
+                                          ^
+ HINT:  You can't put positionals arguments behind the named arguments.
+ select * from dfunc(10,10,20 as a); --fail - a overlaps first positional parameter
+ ERROR:  named parameter "a" overlaps 1. positional parameter
+ drop function dfunc(int, int, int, int);
diff --git a/src/test/regress/sql/polymorphism.sql b/src/test/regress/sql/polymorphism.sql
index c01871d..ff83723 100644
*** a/src/test/regress/sql/polymorphism.sql
--- b/src/test/regress/sql/polymorphism.sql
*************** select dfunc('Hi');
*** 624,626 ****
--- 624,650 ----
  drop function dfunc(int, int, int);
  drop function dfunc(int, int);
  drop function dfunc(text);
+ 
+ -- test function with named params and using named or mixed notation
+ -- fail, unnamed param behind named
+ create function dfunc(a int, b int = 1, c int) returns table (a int, b int, c int) as $$
+   select $1, $2, $3;
+ $$ language sql;
+ 
+ create function dfunc(a int, b int, c int=0, d int = 0) returns table (a int, b int, c int, d int) as $$
+   select $1, $2, $3, $4;
+ $$ language sql;
+ 
+ select (dfunc(10,20,30)).*;
+ select (dfunc(10 as a, 20 as b, 30 as c)).*;
+ select * from dfunc(10 as a, 20 as b);
+ select * from dfunc(10 as b, 20 as a);
+ select * from dfunc(0,0);
+ select * from dfunc(0,0,10 as c);
+ select * from dfunc(0,0,10 as d);
+ 
+ select * from dfunc(10 as x, 20 as b, 30 as c); --fail - unknown param
+ select * from dfunc(10, 20 as b, 30); -- fail using positional notation begind named notation
+ select * from dfunc(10,10,20 as a); --fail - a overlaps first positional parameter
+ 
+ drop function dfunc(int, int, int, int);
