*** ./doc/src/sgml/syntax.sgml.orig	2009-10-02 15:45:01.696472450 +0200
--- ./doc/src/sgml/syntax.sgml	2009-10-02 15:45:51.603472385 +0200
***************
*** 1505,1510 ****
--- 1505,1514 ----
      The list of built-in functions is in <xref linkend="functions">.
      Other functions can be added by the user.
     </para>
+ 
+    <para>
+      See <xref linkend="extend"> for more details.
+    </para>
    </sect2>
  
    <sect2 id="syntax-aggregates">
*** ./doc/src/sgml/xfunc.sgml.orig	2009-10-02 11:09:52.888415595 +0200
--- ./doc/src/sgml/xfunc.sgml	2009-10-02 15:06:35.066231252 +0200
***************
*** 1101,1106 ****
--- 1101,1275 ----
     </para>
    </sect1>
  
+   <sect1 id="xfunc-notation">
+    <title>Calling Functions</title>
+ 
+    <indexterm zone="xfunc-notation">
+     <primary>notation</primary>
+     <secondary>functions</secondary>
+    </indexterm>
+ 
+    <para>
+     <productname>PostgreSQL</productname> supports calling functions with named
+     parameters using <firstterm>positional</firstterm> or
+     <firstterm>named</firstterm> notation.  <firstterm>Named</firstterm>
+     notation makes it easier to recognize the signature of a function. This
+     applies especially to overloaded functions with larger argument lists.  The
+     <firstterm>positional</firstterm> notation calls the function with its
+     argument values in the same order as they are defined in the function
+     declaration.  Using <firstterm>named</firstterm> notation allows passing
+     arguments to a function by name, in any order.  These
+     <firstterm>named</firstterm> and <firstterm>positional</firstterm>
+     notations can be mixed (<firstterm>mixed</firstterm> notation). However,
+     <firstterm>positional</firstterm> notation is only allowed from left to the
+     right in the argument list.  As soon as a <firstterm>named</firstterm>
+     argument appears in the list, <firstterm>named</firstterm> notation must be
+     used for all remaining arguments. Arguments with default values can be
+     omitted. The default values of such arguments will then be used instead.
+     The following examples will illustrate the usage of all three kinds of
+     notation.
+ <programlisting>
+ CREATE OR REPLACE FUNCTION concat_lower_or_upper(a IN text, b IN text, uppercase boolean DEFAULT false)
+ RETURNS text
+ AS 
+ $$
+   SELECT CASE 
+          WHEN $3 THEN UPPER($1) || ' ' || UPPER($2)
+          ELSE LOWER($1) || ' ' || LOWER($2)
+          END;
+ $$ 
+ LANGUAGE SQL IMMUTABLE STRICT;
+ </programlisting>
+     Function <function>concat_lower_or_upper</function> has two mandatory
+     parameters: <literal>a</literal> and <literal>b</literal>. Additionally
+     there is one optional parameter <literal>uppercase</literal> which defaults
+     to <literal>false</literal>.  This function can be called with
+     <firstterm>positional</firstterm>, <firstterm>named</firstterm> or
+     <firstterm>mixed</firstterm> notation. See also <xref
+     linkend="xfunc-sql-parameter-defaults"> for a more detailed explanation of
+     how to call a 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>
+     <literal>Positional</literal> notation is the traditional mechanism for
+     passing arguments to functions in <productname>PostgreSQL</productname>,
+     for example:
+ <screen>
+ SELECT concat_lower_or_upper('Hello', 'World');
+  concat_lower_or_upper
+ -----------------------
+  hello world
+ (1 row)
+ </screen>
+     This calls the function <function>concat_lower_or_upper</function> with
+     both mandatory arguments <literal>a</literal> and <literal>b</literal> in
+     <firstterm>positional</firstterm> notation and omits all default arguments.
+     The argument <literal>uppercase</literal> will have its default value
+     <literal>false</literal> assigned implicitly.  Another example:
+ <screen>
+ SELECT concat_lower_or_upper('Hello', 'World', true);
+  concat_lower_or_upper
+ -----------------------
+  HELLO WORLD
+ (1 row)
+ </screen>
+     Now the function <function>concat_lower_or_upper</function> is called with
+     all arguments in <firstterm>positional</firstterm> notation. In this case
+     <literal>true</literal> will be assigned to the argument
+     <literal>uppercase</literal> explicitly, and the function wil concatenate
+     <literal>a</literal> and <literal>b</literal> in uppercase.
+    </para>
+   </sect2>
+ 
+   <sect2 id="xfunc-notations-named">
+    <title>Using named notation</title>
+ 
+    <indexterm>
+     <primary>function</primary>
+     <secondary>named notation</secondary>
+    </indexterm>
+ 
+    <para>
+     Using <firstterm>named</firstterm> notation this time, the mandatory
+     arguments <literal>a</literal> and <literal>b</literal> are specified with
+     the <literal>AS</literal> keyword.
+ <screen>
+ SELECT concat_lower_or_upper('Hello' AS a, 'World' AS b);
+  concat_lower_or_upper
+ -----------------------
+  hello world
+ (1 row)
+ </screen>
+     Again, the default argument <literal>uppercase</literal> is omitted and set
+     to <literal>false</literal> implicitly.  The advantage of using
+     <literal>named</literal> notation is that the arguments may be specified in
+     any order, for example:
+ <screen>
+ SELECT concat_lower_or_upper('Hello' AS a, 'World' AS b, true AS uppercase);
+  concat_lower_or_upper
+ -----------------------
+  HELLO WORLD
+ (1 row)
+ 
+ SELECT concat_lower_or_upper('Hello' AS a, true AS uppercase, 'World' AS b);
+  concat_lower_or_upper
+ -----------------------
+  HELLO WORLD
+ (1 row)
+ </screen>
+    </para>
+    <note>
+     <para>
+      Variadic functions cannot be called using <firstterm>named</firstterm>
+      or <firstterm>mixed</firstterm> notation.
+     </para>
+    </note>
+   </sect2>
+  
+   <sect2 id="xfunc-notations-mixed">
+    <title>Using mixed notation</title>
+ 
+    <indexterm>
+     <primary>function</primary>
+     <secondary>mixed notation</secondary>
+    </indexterm>
+ 
+    <para>
+     The <literal>mixed</literal> notation combines
+     <firstterm>positional</firstterm> and <firstterm>named</firstterm>
+     notation. However, as already mentioned, named arguments cannot precede
+     positional arguments.
+ <screen>
+ SELECT concat_lower_or_upper('Hello', 'World' AS b, true AS uppercase);
+  concat_lower_or_upper
+ -----------------------
+  HELLO WORLD
+ (1 row)
+ </screen>
+     The above query is legal, since the argument <literal>a</literal> is
+     specified using <firstterm>positional</firstterm> notation, before any
+     named arguments. However, the following example will fail, since
+     <literal>'Hello'</literal> is specified using positional notation after the
+     named argument <literal>b</literal>.
+ <screen>
+ SELECT concat_lower_or_upper('World' AS b, 'Hello', true AS uppercase);
+ ERROR:  expected named argument
+ LINE 1: SELECT concat_lower_or_upper('World' AS b, 'Hello', true AS ...
+                                                    ^
+ HINT:  You can't put positional arguments after named arguments.
+ </screen>
+     </para>
+    </sect2>
+   </sect1>
+ 
    <sect1 id="xfunc-volatility">
     <title>Function Volatility Categories</title>
  
*** ./src/backend/catalog/namespace.c.orig	2009-10-02 11:09:52.901413816 +0200
--- ./src/backend/catalog/namespace.c	2009-10-02 15:35:03.111310678 +0200
***************
*** 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"
***************
*** 188,193 ****
--- 189,198 ----
  static void RemoveTempRelations(Oid tempNamespaceId);
  static void RemoveTempRelationsCallback(int code, Datum arg);
  static void NamespaceCallback(Datum arg, int cacheid, ItemPointer tuplePtr);
+ static bool VerifyCandidateNamedNotation(HeapTuple proctup, int pronargs, int nargs, List *argnames, 
+ 						bool expand_defaults, int pronargdefaults, 
+ 						bool *use_defaults, int **proargidxs);
+ 
  
  /* These don't really need to appear in any header file */
  Datum		pg_table_is_visible(PG_FUNCTION_ARGS);
***************
*** 604,610 ****
   * 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;
--- 609,615 ----
   * such an entry it should react as though the call were ambiguous.
   */
  FuncCandidateList
! FuncnameGetCandidates(List *names, int nargs, List *argnames,
  					  bool expand_variadic, bool expand_defaults)
  {
  	FuncCandidateList resultList = NULL;
***************
*** 646,688 ****
  		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))
  		{
--- 651,722 ----
  		int			effective_nargs;
  		int			pathpos = 0;
  		bool		variadic;
! 		bool		use_defaults = false;		/* make compiler quiet */
  		Oid			va_elem_type;
  		FuncCandidateList newResult;
+ 		int		*proargidxs = NULL;
  
! 		/* Try to attach names when mixed or named notation is used. */
! 		if (argnames != NIL)
  		{
! 			/*
! 			 * Mixed or named notation
! 			 *
! 			 * Variadic functions can't be called using named or mixed
! 			 * notation.
! 			 */
! 			if (OidIsValid(procform->provariadic))
! 				continue;
! 
! 			if (!VerifyCandidateNamedNotation(proctup, pronargs, nargs,
! 										    argnames,
! 										    expand_defaults,
! 										    procform->pronargdefaults,
! 										    &use_defaults,
! 										    &proargidxs))
! 				continue;
! 
! 			va_elem_type = InvalidOid;
! 			variadic = false; 
  		}
  		else
  		{
! 			/*
! 			 * Positional notation 
! 			 * 
! 			 * 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))
  		{
***************
*** 722,727 ****
--- 756,771 ----
  		newResult->pathpos = pathpos;
  		newResult->oid = HeapTupleGetOid(proctup);
  		newResult->nargs = effective_nargs;
+ 
+ 		/*
+ 		 * Save proargidxs in newResult. It's needed later to adjust
+ 		 * the argument types to be the types corresponding to the
+ 		 * named arguments (if any), and also to assign positions to
+ 		 * any NamedArgExpr arguments after the best candidate is
+ 		 * determined. The former could be done here, but we leave
+ 		 * both for the caller to do.
+ 		 */
+ 		newResult->proargidxs = proargidxs; 
  		memcpy(newResult->args, procform->proargtypes.values,
  			   pronargs * sizeof(Oid));
  		if (variadic)
***************
*** 886,891 ****
--- 930,1065 ----
  }
  
  /*
+  * VerifyCandidateNameNotation
+  *      Given a pg_proc heap tuple and its list of named arguments,
+  *      verify a possible notation candidate (these are named,
+  *      positional or mixed notation currently), which matches
+  *      a possible function signature candidate. Returns true if the
+  *      argument list can be verified against the given function,
+  *      otherwise false is returned.
+  */
+ static bool
+ VerifyCandidateNamedNotation(HeapTuple proctup, int pronargs, int nargs, List *argnames, 
+ 						bool expand_defaults, int pronargdefaults, 
+ 						bool *use_defaults, int **proargidxs)
+ {
+ 	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;
+ 	bool	argfilling[FUNC_MAX_ARGS];		/* function parameters occupation */
+ 
+     /* used for assertion only */
+ #ifdef USE_ASSERT_CHECKING
+ 	CallNotationType notation = CALL_NOTATION_POSITIONAL;
+ #endif
+ 
+ 	Assert(argnames != NIL);
+ 
+ 	/* Ignore if not enough default expressions */
+ 	if (nargs + pronargdefaults < pronargs)
+ 		return false;
+ 
+ 	/* Ignore if defaults are requested but not expanded */
+ 	if (nargs < pronargs && !expand_defaults)
+ 		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);
+ 
+ 	/* 
+ 	 * pronargs equal to nargs means explicit arguments (no defaults)
+ 	 */
+ 	*proargidxs = palloc(nargs * sizeof(int));
+ 	for (i = 0; i < pronargs; i++)
+ 		argfilling[i] = false;
+ 
+ 	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 && p_argmodes[i] != FUNC_PARAM_VARIADIC))
+ 					continue;
+ 				if (p_argnames[i] && strcmp(p_argnames[i], argname) == 0)
+ 				{
+ 					/*  protect us against duplicated entries from bad written  mixed notation */
+ 					if (argfilling[pp])
+ 						return false;
+ 
+ 					found = true;
+ 					argfilling[pp] = true;
+ 					(*proargidxs)[ap] = pp;
+ 					break;
+ 				}
+ 				/* increase only for IN and INOUT args */
+ 				pp++;
+ 			}
+ 			/* any name isn't in proargnames, abort */
+ 			if (!found)
+ 				return false;
+ 
+ #ifdef USE_ASSERT_CHECKING
+ 			notation = CALL_NOTATION_NAMED;
+ #endif
+ 		}
+ 		else
+ 		{
+ 			Assert(notation == CALL_NOTATION_POSITIONAL);
+ 
+ 			/* positional parameter */
+ 			argfilling[ap] = true;
+ 			(*proargidxs)[ap] = ap;
+ 		}
+ 		ap++;
+ 	}
+ 	
+ 	/*
+ 	 * This function is only called for named and mixed notation, and
+ 	 * the last argument must be named in either case.
+ 	 */
+ 	Assert(notation == CALL_NOTATION_NAMED);
+ 
+ 	/* Check for default arguments */
+ 	if (nargs < pronargs)
+ 	{
+ 		int first_arg_with_default = pronargs - pronargdefaults;
+ 
+ 		for (i = 0; i < pronargs; i++)
+ 		{
+ 			/* When there's a param still missing and no default is available, exit */
+ 			if (!argfilling[i] && i < first_arg_with_default)
+ 				return false;
+ 		}
+ 		*use_defaults = true;
+ 	}
+ 
+ 	return true;
+ }
+ 
+ /*
   * FunctionIsVisible
   *		Determine whether a function (identified by OID) is visible in the
   *		current search path.  Visible means "would be found by searching
***************
*** 932,938 ****
  		visible = false;
  
  		clist = FuncnameGetCandidates(list_make1(makeString(proname)),
! 									  nargs, false, false);
  
  		for (; clist; clist = clist->next)
  		{
--- 1106,1112 ----
  		visible = false;
  
  		clist = FuncnameGetCandidates(list_make1(makeString(proname)),
! 									  nargs, NIL, false, false);
  
  		for (; clist; clist = clist->next)
  		{
*** ./src/backend/catalog/pg_aggregate.c.orig	2009-10-02 11:09:52.908413835 +0200
--- ./src/backend/catalog/pg_aggregate.c	2009-10-02 11:10:41.002289003 +0200
***************
*** 321,327 ****
  	 * 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);
  
--- 321,327 ----
  	 * 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);
  
*** ./src/backend/catalog/pg_proc.c.orig	2009-10-02 11:09:52.918291271 +0200
--- ./src/backend/catalog/pg_proc.c	2009-10-02 15:36:10.194311900 +0200
***************
*** 101,106 ****
--- 101,108 ----
  	bool		is_update;
  	ObjectAddress myself,
  				referenced;
+ 	bool		isnull;
+ 	Datum		prooldargnames;
  	int			i;
  
  	/*
***************
*** 403,409 ****
  		if (oldproc->pronargdefaults != 0)
  		{
  			Datum		proargdefaults;
- 			bool		isnull;
  			List	   *oldDefaults;
  			ListCell   *oldlc;
  			ListCell   *newlc;
--- 405,410 ----
***************
*** 442,447 ****
--- 443,525 ----
  				newlc = lnext(newlc);
  			}
  		}
+ 		
+ 		/*
+ 		 * If there are named parameters, check to make sure the names
+ 		 * have not been changed. Any change can break exiting calls
+ 		 * when named parameters are used. Only IN and INOUT
+ 		 * parameters are checked.
+ 		 */
+ 		prooldargnames = SysCacheGetAttr(PROCNAMEARGSNSP, oldtup, 
+ 									Anum_pg_proc_proargnames,
+ 									&isnull);
+ 		if (!isnull)
+ 		{
+ 			Oid	*p_oldargtypes;
+ 			char	**p_oldargnames;
+ 			char	*p_oldargmodes;
+ 			int	pronoldallargs;
+ 			char		*p_modes = NULL;
+ 			char		**p_names = NULL;
+ 			int			j;
+ 				
+ 			pronoldallargs = get_func_arg_info(oldtup, &p_oldargtypes, 
+ 											&p_oldargnames,
+ 											&p_oldargmodes);
+ 			Assert(PointerIsValid(p_oldargnames));
+ 			
+ 			if (parameterModes != PointerGetDatum(NULL))
+ 			{
+ 				ArrayType  *modesArray = (ArrayType *) DatumGetPointer(parameterModes);
+ 				
+ 				p_modes = (char *) ARR_DATA_PTR(modesArray);
+ 			}	
+ 			
+ 			if (parameterNames != PointerGetDatum(NULL))
+ 			{
+ 				Datum	*elems;
+ 				int		nelems;
+ 				
+ 				deconstruct_array(DatumGetArrayTypeP(parameterNames),
+ 							TEXTOID, -1, false, 'i',
+ 							&elems, NULL, &nelems);
+ 				Assert(nelems == allParamCount);
+ 				p_names = (char **) palloc(sizeof(char *) * nelems);
+ 				for (i = 0; i < nelems; i++)
+ 					p_names[i] = TextDatumGetCString(elems[i]);
+ 			}
+ 			
+ 			/* compare names of IN and INOUT parameters */
+ 			for (i = 0, j = 0; i < pronoldallargs; i++)
+ 			{
+ 				/* skip old output arguments */
+ 				if (p_oldargmodes != NULL && (p_oldargmodes[i] == PROARGMODE_OUT ||
+ 								    p_oldargmodes[i] == PROARGMODE_TABLE))
+ 					continue;
+ 				/* find first new input arguments */
+ 				for ( ;j < allParamCount; j++)
+ 					if (p_modes == NULL || (p_modes != NULL && (p_modes[j] == PROARGMODE_IN ||
+ 											p_modes[j] == PROARGMODE_INOUT ||
+ 											p_modes[j] == PROARGMODE_VARIADIC)))
+ 						break;
+ 
+ 				/* j should to be valid index */
+ 				Assert(j < allParamCount);
+ 				if (p_oldargnames != NULL && *p_oldargnames[i] != '\0')
+ 				{
+ 					bool	valid;
+ 					/* when original argname is same as new name, then name is valided */
+ 					valid = p_names != NULL && *p_names[j] != '\0' 
+ 							&& strcmp(p_oldargnames[i], p_names[j]) == 0;
+ 					if (!valid)		
+ 						ereport(ERROR,
+ 								(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
+ 								 errmsg("cannot change name of existing input parameter"),
+ 								 errhint("Use DROP FUNCTION first.")));
+ 				}
+ 				j++;
+ 			}
+ 		 }
  
  		/* Can't change aggregate or window-function status, either */
  		if (oldproc->proisagg != isAgg)
*** ./src/backend/nodes/copyfuncs.c.orig	2009-09-23 01:43:37.000000000 +0200
--- ./src/backend/nodes/copyfuncs.c	2009-10-02 11:10:41.005288929 +0200
***************
*** 1013,1018 ****
--- 1013,1019 ----
  	COPY_SCALAR_FIELD(funcresulttype);
  	COPY_SCALAR_FIELD(funcretset);
  	COPY_SCALAR_FIELD(funcformat);
+ 	COPY_SCALAR_FIELD(notation);
  	COPY_NODE_FIELD(args);
  	COPY_LOCATION_FIELD(location);
  
***************
*** 1020,1025 ****
--- 1021,1042 ----
  }
  
  /*
+  * _copyNamedArgExpr *
+  */
+ static NamedArgExpr *
+ _copyNamedArgExpr(NamedArgExpr *from)
+ {
+ 	NamedArgExpr *newnode = makeNode(NamedArgExpr);
+ 	
+ 	COPY_STRING_FIELD(name);
+ 	COPY_NODE_FIELD(arg);
+ 	COPY_SCALAR_FIELD(position);
+ 	COPY_LOCATION_FIELD(location);
+ 	
+ 	return newnode;
+ }
+ 
+ /*
   * _copyOpExpr
   */
  static OpExpr *
***************
*** 3575,3580 ****
--- 3592,3600 ----
  		case T_FuncExpr:
  			retval = _copyFuncExpr(from);
  			break;
+ 		case T_NamedArgExpr:
+ 			retval = _copyNamedArgExpr(from);
+ 			break;
  		case T_OpExpr:
  			retval = _copyOpExpr(from);
  			break;
*** ./src/backend/nodes/equalfuncs.c.orig	2009-09-23 01:43:38.000000000 +0200
--- ./src/backend/nodes/equalfuncs.c	2009-10-02 11:10:41.006289067 +0200
***************
*** 235,240 ****
--- 235,241 ----
  		b->funcformat != COERCE_DONTCARE)
  		return false;
  
+ 	COMPARE_SCALAR_FIELD(notation);
  	COMPARE_NODE_FIELD(args);
  	COMPARE_LOCATION_FIELD(location);
  
***************
*** 242,247 ****
--- 243,259 ----
  }
  
  static bool
+ _equalNamedArgExpr(NamedArgExpr *a, NamedArgExpr *b)
+ {
+ 	COMPARE_STRING_FIELD(name);
+ 	COMPARE_NODE_FIELD(arg);
+ 	COMPARE_SCALAR_FIELD(position);
+ 	COMPARE_LOCATION_FIELD(location);
+ 	
+ 	return true;
+ }
+ 
+ static bool
  _equalOpExpr(OpExpr *a, OpExpr *b)
  {
  	COMPARE_SCALAR_FIELD(opno);
***************
*** 2365,2370 ****
--- 2377,2385 ----
  		case T_FuncExpr:
  			retval = _equalFuncExpr(a, b);
  			break;
+ 		case T_NamedArgExpr:
+ 			retval = _equalNamedArgExpr(a, b);
+ 			break;
  		case T_OpExpr:
  			retval = _equalOpExpr(a, b);
  			break;
*** ./src/backend/nodes/makefuncs.c.orig	2009-10-02 11:09:52.947291561 +0200
--- ./src/backend/nodes/makefuncs.c	2009-10-02 11:10:41.007290532 +0200
***************
*** 342,347 ****
--- 342,348 ----
  	funcexpr->funcresulttype = rettype;
  	funcexpr->funcretset = false;		/* only allowed case here */
  	funcexpr->funcformat = fformat;
+ 	funcexpr->notation = CALL_NOTATION_POSITIONAL;
  	funcexpr->args = args;
  	funcexpr->location = -1;
  
*** ./src/backend/nodes/nodeFuncs.c.orig	2009-10-02 11:09:52.949290938 +0200
--- ./src/backend/nodes/nodeFuncs.c	2009-10-02 11:10:41.019290724 +0200
***************
*** 69,74 ****
--- 69,77 ----
  		case T_FuncExpr:
  			type = ((FuncExpr *) expr)->funcresulttype;
  			break;
+ 		case T_NamedArgExpr:
+ 			type = exprType((Node *)((NamedArgExpr *) expr)->arg);
+ 			break;
  		case T_OpExpr:
  			type = ((OpExpr *) expr)->opresulttype;
  			break;
***************
*** 259,264 ****
--- 262,269 ----
  					return coercedTypmod;
  			}
  			break;
+ 		case T_NamedArgExpr:
+ 			return exprTypmod((Node *) ((NamedArgExpr *) expr)->arg);
  		case T_SubLink:
  			{
  				SubLink    *sublink = (SubLink *) expr;
***************
*** 676,681 ****
--- 681,689 ----
  								  exprLocation((Node *) fexpr->args));
  			}
  			break;
+ 		case T_NamedArgExpr:
+ 			loc = ((NamedArgExpr *) expr)->location;
+ 			break;
  		case T_OpExpr:
  		case T_DistinctExpr:	/* struct-equivalent to OpExpr */
  		case T_NullIfExpr:		/* struct-equivalent to OpExpr */
***************
*** 1345,1355 ****
--- 1353,1366 ----
  			break;
  		case T_PlaceHolderInfo:
  			return walker(((PlaceHolderInfo *) node)->ph_var, context);
+ 		case T_NamedArgExpr:
+ 			return walker(((NamedArgExpr *) node)->arg, context);
  		default:
  			elog(ERROR, "unrecognized node type: %d",
  				 (int) nodeTag(node));
  			break;
  	}
+ 	
  	return false;
  }
  
***************
*** 2019,2024 ****
--- 2030,2045 ----
  				return (Node *) newnode;
  			}
  			break;
+ 		case T_NamedArgExpr:
+ 			{
+ 				NamedArgExpr *nexpr = (NamedArgExpr *) node;
+ 				NamedArgExpr *newnode;
+ 				
+ 				FLATCOPY(newnode, nexpr, NamedArgExpr);
+ 				MUTATE(newnode->arg, nexpr->arg, Expr *);
+ 				return (Node *) newnode;
+ 			}
+ 			break;
  		default:
  			elog(ERROR, "unrecognized node type: %d",
  				 (int) nodeTag(node));
*** ./src/backend/nodes/outfuncs.c.orig	2009-09-17 22:49:28.000000000 +0200
--- ./src/backend/nodes/outfuncs.c	2009-10-02 11:10:41.021288487 +0200
***************
*** 871,881 ****
--- 871,893 ----
  	WRITE_OID_FIELD(funcresulttype);
  	WRITE_BOOL_FIELD(funcretset);
  	WRITE_ENUM_FIELD(funcformat, CoercionForm);
+ 	WRITE_ENUM_FIELD(notation, CallNotationType);
  	WRITE_NODE_FIELD(args);
  	WRITE_LOCATION_FIELD(location);
  }
  
  static void
+ _outNamedArgExpr(StringInfo str, NamedArgExpr *node)
+ {
+ 	WRITE_NODE_TYPE("NAMEDARGEXPR");
+ 	
+ 	WRITE_NODE_FIELD(arg);
+ 	WRITE_STRING_FIELD(name);
+ 	WRITE_INT_FIELD(position);
+ 	WRITE_LOCATION_FIELD(location);
+ }
+ 
+ static void
  _outOpExpr(StringInfo str, OpExpr *node)
  {
  	WRITE_NODE_TYPE("OPEXPR");
***************
*** 2514,2519 ****
--- 2526,2534 ----
  			case T_FuncExpr:
  				_outFuncExpr(str, obj);
  				break;
+ 			case T_NamedArgExpr:
+ 				_outNamedArgExpr(str, obj);
+ 				break;
  			case T_OpExpr:
  				_outOpExpr(str, obj);
  				break;
*** ./src/backend/nodes/readfuncs.c.orig	2009-10-02 11:09:52.978412980 +0200
--- ./src/backend/nodes/readfuncs.c	2009-10-02 11:10:41.022289952 +0200
***************
*** 519,524 ****
--- 519,525 ----
  	READ_OID_FIELD(funcresulttype);
  	READ_BOOL_FIELD(funcretset);
  	READ_ENUM_FIELD(funcformat, CoercionForm);
+ 	READ_ENUM_FIELD(notation, CallNotationType);
  	READ_NODE_FIELD(args);
  	READ_LOCATION_FIELD(location);
  
***************
*** 526,531 ****
--- 527,548 ----
  }
  
  /*
+  * _readNamedArgExpr
+  */
+ static NamedArgExpr *
+ _readNamedArgExpr(void)
+ {
+ 	READ_LOCALS(NamedArgExpr);
+ 	
+ 	READ_NODE_FIELD(arg);
+ 	READ_STRING_FIELD(name);
+ 	READ_INT_FIELD(position);
+ 	READ_LOCATION_FIELD(location);
+ 	
+ 	READ_DONE();
+ }
+ 
+ /*
   * _readOpExpr
   */
  static OpExpr *
***************
*** 1207,1212 ****
--- 1224,1231 ----
  		return_value = _readArrayRef();
  	else if (MATCH("FUNCEXPR", 8))
  		return_value = _readFuncExpr();
+ 	else if (MATCH("NAMEDARGEXPR", 12))
+ 		return_value = _readNamedArgExpr();
  	else if (MATCH("OPEXPR", 6))
  		return_value = _readOpExpr();
  	else if (MATCH("DISTINCTEXPR", 12))
*** ./src/backend/optimizer/util/clauses.c.orig	2009-10-02 11:09:52.987288528 +0200
--- ./src/backend/optimizer/util/clauses.c	2009-10-02 15:37:57.858436383 +0200
***************
*** 94,105 ****
  					   bool *haveNull, bool *forceFalse);
  static Expr *simplify_boolean_equality(Oid opno, 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,
--- 94,109 ----
  					   bool *haveNull, bool *forceFalse);
  static Expr *simplify_boolean_equality(Oid opno, List *args);
  static Expr *simplify_function(Oid funcid,
! 				  Oid result_type, int32 result_typmod,
! 				  CallNotationType notation, 
! 				  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 List *reorder_arguments(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,
***************
*** 2133,2138 ****
--- 2137,2143 ----
  		 */
  		simple = simplify_function(expr->funcid,
  								   expr->funcresulttype, exprTypmod(node),
+ 								   expr->notation,
  								   &args,
  								   true, context);
  		if (simple)				/* successfully simplified it */
***************
*** 2180,2185 ****
--- 2185,2191 ----
  		 */
  		simple = simplify_function(expr->opfuncid,
  								   expr->opresulttype, -1,
+ 								   CALL_NOTATION_POSITIONAL,
  								   &args,
  								   true, context);
  		if (simple)				/* successfully simplified it */
***************
*** 2273,2278 ****
--- 2279,2285 ----
  			 */
  			simple = simplify_function(expr->opfuncid,
  									   expr->opresulttype, -1,
+ 									   CALL_NOTATION_POSITIONAL,
  									   &args,
  									   false, context);
  			if (simple)			/* successfully simplified it */
***************
*** 2465,2470 ****
--- 2472,2478 ----
  
  		simple = simplify_function(outfunc,
  								   CSTRINGOID, -1,
+ 								   CALL_NOTATION_POSITIONAL,
  								   &args,
  								   true, context);
  		if (simple)				/* successfully simplified output fn */
***************
*** 2483,2488 ****
--- 2491,2497 ----
  
  			simple = simplify_function(infunc,
  									   expr->resulttype, -1,
+ 									   CALL_NOTATION_POSITIONAL,
  									   &args,
  									   true, context);
  			if (simple)			/* successfully simplified input fn */
***************
*** 3249,3254 ****
--- 3258,3264 ----
   */
  static Expr *
  simplify_function(Oid funcid, Oid result_type, int32 result_typmod,
+ 				  CallNotationType notation,
  				  List **args,
  				  bool allow_inline,
  				  eval_const_expressions_context *context)
***************
*** 3270,3277 ****
  	if (!HeapTupleIsValid(func_tuple))
  		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,
--- 3280,3290 ----
  	if (!HeapTupleIsValid(func_tuple))
  		elog(ERROR, "cache lookup failed for function %u", funcid);
  
+ 	/* When named notation is used, reorder arguments and if we need, then add defaults */
+ 	if (notation == CALL_NOTATION_NAMED)
+ 		*args = reorder_arguments(*args, result_type, func_tuple, context);
  	/* While we have the tuple, check if we need to add defaults */
! 	else 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,
***************
*** 3287,3293 ****
  }
  
  /*
!  * add_function_defaults: add missing function arguments from its defaults
   *
   * It is possible for some of the defaulted arguments to be polymorphic;
   * therefore we can't assume that the default expressions have the correct
--- 3300,3443 ----
  }
  
  /*
!  * This function changes the order of any arg in arglist. When some
!  * arguments are missing, then it uses the defaults.
!  */
! static List *
! reorder_arguments(List *args, Oid result_type, HeapTuple func_tuple,
! 					  eval_const_expressions_context *context)
! {
! 	Form_pg_proc funcform = (Form_pg_proc) GETSTRUCT(func_tuple);
! 	int	nargs;
! 	int	firstdefpos = 0;		/* be compiler quiet */
! 	List	*defaults;
! 	List		*newargs;
! 	ListCell	*lc;
! 	Oid		rettype;
! 	Oid			actual_arg_types[FUNC_MAX_ARGS];
! 	Oid			declared_arg_types[FUNC_MAX_ARGS];
! 	int		i;
! 	Bitmapset		*defargidxs;
! 	
! 	nargs = list_length(args);
! 	
! 	/* Load defaults, when it's necessary */
! 	if (nargs < funcform->pronargs)
! 	{
! 		Datum		proargdefaults;
! 		bool	isnull;
! 		char	*str;
! 		
! 		proargdefaults = SysCacheGetAttr(PROCOID, func_tuple,
! 									 Anum_pg_proc_proargdefaults,
! 									 &isnull);
! 		if (isnull)
! 			elog(ERROR, "not enough default arguments");
! 		str = TextDatumGetCString(proargdefaults);
! 		defaults = (List *) stringToNode(str);
! 		Assert(IsA(defaults, List));
! 		
! 		firstdefpos = funcform->pronargs - funcform->pronargdefaults;
! 		pfree(str);
! 	}
! 	else
! 	{
! 		/* There are no defaults */
! 		defaults = NIL;
! 	}
! 	
! 	i = 0;
! 	newargs = NIL;
! 	defargidxs = NULL;
! 	foreach (lc, args)
! 	{
! 		Node *node = (Node *) lfirst(lc);
! 		
! 		/* process first n positional arguments */
! 		if (!IsA(node, NamedArgExpr))
! 		{
! 			newargs = lappend(newargs, node);
! 			actual_arg_types[i] = exprType(node);
! 			i++;
! 		}
! 		else
! 		{
! 			ListCell  *l;
! 			bool	  found;
! 		
! 			/* process other necessary arguments */
! 			for ( ; i < funcform->pronargs; i++)
! 			{
! 				found = false;
! 				for_each_cell (l, lc)
! 				{
! 					NamedArgExpr *namedarg = (NamedArgExpr *) lfirst(l);
! 					
! 					Assert(IsA(namedarg, NamedArgExpr));
! 					
! 					if (namedarg->position == i)
! 					{
! 						newargs = lappend(newargs, namedarg->arg);
! 						actual_arg_types[i] = exprType((Node *) namedarg->arg);
! 						found = true;
! 						break;
! 					}
! 				}
! 				
! 				/* When there are no argument for specified position, use default */
! 				if (!found)
! 				{
! 					Node	*defexpr;
! 					
! 					Assert(defaults != NIL);
! 					defexpr = (Node *) list_nth(defaults, i - firstdefpos);
! 					newargs = lappend(newargs, defexpr);
! 					actual_arg_types[i] = exprType(defexpr);
! 					defargidxs = bms_add_member(defargidxs, i);
! 					nargs++;
! 				}			
! 			}
! 			break;
! 		}
! 	}
! 	
! 	Assert(list_length(newargs) == funcform->pronargs);
! 	Assert(nargs == funcform->pronargs);
! 	
! 	memcpy(declared_arg_types, funcform->proargtypes.values,
! 		   funcform->pronargs * sizeof(Oid));
! 	rettype = enforce_generic_type_consistency(actual_arg_types,
! 											   declared_arg_types,
! 											   nargs,
! 											   funcform->prorettype,
! 											   false);
! 	/* let's just check we got the same answer as the parser did ... */
! 	if (rettype != result_type)
! 		elog(ERROR, "function's resolved result type changed during planning");
! 
! 	/* perform any necessary typecasting of arguments */
! 	make_fn_arguments(NULL, newargs, actual_arg_types, declared_arg_types);
! 
! 	/*
! 	 * Lastly, we have to recursively simplify the arguments we just added
! 	 * (but don't recurse on the ones passed in, as we already did those).
! 	 * This isn't merely an optimization, it's *necessary* since there could
! 	 * be functions with defaulted arguments down in there.
! 	 */
! 	i = 0;
! 	foreach(lc, newargs)
! 	{
! 		if (bms_is_member(i, defargidxs))
! 			lfirst(lc) = eval_const_expressions_mutator((Node *) lfirst(lc),
! 													context);
! 	}
! 	bms_free(defargidxs);
! 
! 	return newargs;
! }
! 
! /*
!  * add_function_defaults_positional_notation: add missing function arguments from its defaults
   *
   * It is possible for some of the defaulted arguments to be polymorphic;
   * therefore we can't assume that the default expressions have the correct
*** ./src/backend/parser/gram.y.orig	2009-09-23 01:43:38.000000000 +0200
--- ./src/backend/parser/gram.y	2009-10-02 15:59:40.739471599 +0200
***************
*** 137,142 ****
--- 137,145 ----
  static List *mergeTableFuncParameters(List *func_args, List *columns);
  static TypeName *TableFuncTypeName(List *columns);
  
+ static List *AppendFuncParameter(List *list, FunctionParameter *p,
+ 								    int location, base_yyscan_t yyscanner);
+ 
  %}
  
  %pure-parser
***************
*** 348,353 ****
--- 351,358 ----
  %type <node>	def_arg columnElem where_clause where_or_current_clause
  				a_expr b_expr c_expr func_expr AexprConst indirection_el
  				columnref in_expr having_clause func_table array_expr
+ %type <list>	func_arg_list
+ %type <node> func_arg_expr
  %type <list>	row type_list array_expr_list
  %type <node>	case_expr case_arg when_clause case_default
  %type <list>	when_clause_list
***************
*** 4748,4754 ****
  
  func_args_list:
  			func_arg								{ $$ = list_make1($1); }
! 			| func_args_list ',' func_arg			{ $$ = lappend($1, $3); }
  		;
  
  /*
--- 4753,4759 ----
  
  func_args_list:
  			func_arg								{ $$ = list_make1($1); }
! 			| func_args_list ',' func_arg						{ $$ = AppendFuncParameter($1, $3, @3, yyscanner); }
  		;
  
  /*
***************
*** 4762,4769 ****
  
  func_args_with_defaults_list:
  		func_arg_with_default						{ $$ = list_make1($1); }
! 		| func_args_with_defaults_list ',' func_arg_with_default
! 													{ $$ = lappend($1, $3); }
  		;
  
  /*
--- 4767,4773 ----
  
  func_args_with_defaults_list:
  		func_arg_with_default						{ $$ = list_make1($1); }
! 		| func_args_with_defaults_list ',' func_arg_with_default        { $$ = AppendFuncParameter($1, $3, @3, yyscanner); }
  		;
  
  /*
***************
*** 8944,8950 ****
  					n->location = @1;
  					$$ = (Node *)n;
  				}
! 			| func_name '(' expr_list ')' over_clause
  				{
  					FuncCall *n = makeNode(FuncCall);
  					n->funcname = $1;
--- 8948,8954 ----
  					n->location = @1;
  					$$ = (Node *)n;
  				}
! 			| func_name '(' func_arg_list ')' over_clause
  				{
  					FuncCall *n = makeNode(FuncCall);
  					n->funcname = $1;
***************
*** 8956,8962 ****
  					n->location = @1;
  					$$ = (Node *)n;
  				}
! 			| func_name '(' VARIADIC a_expr ')' over_clause
  				{
  					FuncCall *n = makeNode(FuncCall);
  					n->funcname = $1;
--- 8960,8966 ----
  					n->location = @1;
  					$$ = (Node *)n;
  				}
! 			| func_name '(' VARIADIC func_arg_expr ')' over_clause
  				{
  					FuncCall *n = makeNode(FuncCall);
  					n->funcname = $1;
***************
*** 8968,8974 ****
  					n->location = @1;
  					$$ = (Node *)n;
  				}
! 			| func_name '(' expr_list ',' VARIADIC a_expr ')' over_clause
  				{
  					FuncCall *n = makeNode(FuncCall);
  					n->funcname = $1;
--- 8972,8978 ----
  					n->location = @1;
  					$$ = (Node *)n;
  				}
! 			| func_name '(' func_arg_list ',' VARIADIC func_arg_expr ')' over_clause
  				{
  					FuncCall *n = makeNode(FuncCall);
  					n->funcname = $1;
***************
*** 8980,8986 ****
  					n->location = @1;
  					$$ = (Node *)n;
  				}
! 			| func_name '(' ALL expr_list ')' over_clause
  				{
  					FuncCall *n = makeNode(FuncCall);
  					n->funcname = $1;
--- 8984,8990 ----
  					n->location = @1;
  					$$ = (Node *)n;
  				}
! 			| func_name '(' ALL func_arg_list ')' over_clause
  				{
  					FuncCall *n = makeNode(FuncCall);
  					n->funcname = $1;
***************
*** 8996,9002 ****
  					n->location = @1;
  					$$ = (Node *)n;
  				}
! 			| func_name '(' DISTINCT expr_list ')' over_clause
  				{
  					FuncCall *n = makeNode(FuncCall);
  					n->funcname = $1;
--- 9000,9006 ----
  					n->location = @1;
  					$$ = (Node *)n;
  				}
! 			| func_name '(' DISTINCT func_arg_list ')' over_clause
  				{
  					FuncCall *n = makeNode(FuncCall);
  					n->funcname = $1;
***************
*** 9719,9724 ****
--- 9723,9755 ----
  				}
  		;
  
+ /* used for named notation support
+  */
+ func_arg_list:  func_arg_expr
+ 				{
+ 					$$ = list_make1($1);
+ 				}
+ 			| func_arg_list ',' func_arg_expr
+ 				{
+ 					$$ = lappend($1, $3);
+ 				}
+ 		;
+ 	
+ func_arg_expr:
+ 		a_expr
+ 				{
+ 					$$ = $1;
+ 				}
+ 			| a_expr AS param_name
+ 				{
+ 					NamedArgExpr *fa = makeNode(NamedArgExpr);
+ 					fa->arg = (Expr *) $1;
+ 					fa->name = $3;
+ 					fa->location = @1;
+ 					$$ = (Node *) fa;
+ 				}
+ 		;
+ 		
  type_list:	Typename								{ $$ = list_make1($1); }
  			| type_list ',' Typename				{ $$ = lappend($1, $3); }
  		;
***************
*** 10185,10194 ****
  					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);
--- 10216,10237 ----
  					t->location = @1;
  					$$ = makeStringConstCast($2, @2, t);
  				}
! 			| func_name '(' func_arg_list ')' Sconst
  				{
  					/* generic syntax with a type modifier */
  					TypeName *t = makeTypeNameFromNameList($1);
+ 					ListCell *lc;
+ 					
+ 					/* Don't allow NamedArgExpr in this context */
+ 					foreach(lc, $3)
+ 					{
+ 						if (IsA((Node *) lfirst(lc), NamedArgExpr))
+ 							ereport(ERROR,
+ 								    (errcode(ERRCODE_SYNTAX_ERROR),
+ 								     errmsg("type modifier has name"),
+ 								     errhint("Don't use keyword \"AS\" in this context"),
+ 								     parser_errposition(exprLocation((Node *) lfirst(lc)))));
+ 					}
  					t->typmods = $3;
  					t->location = @1;
  					$$ = makeStringConstCast($5, @5, t);
***************
*** 11288,11293 ****
--- 11331,11376 ----
  }
  
  /*
+  * Append function parameter to function's parameter list. Reject 
+  * parameters with non-unique param_name with same proargmode.
+  * It's enough for sql, plperl, plpython language, but not for
+  * plpgsql. 
+  * 
+  * Function f1(IN a int, IN b int, OUT a int, OUT b int)
+  * is same as f1(INOUT a int, INOUT b int) and is valid for
+  * languages without variables for OUT parameters. Full check
+  * must be done by language validation handlers, when it's 
+  * necessary.
+  */
+ static List *
+ AppendFuncParameter(List *list, FunctionParameter *p, int location, base_yyscan_t yyscanner)
+ {
+ 	ListCell    *lc;
+ 	
+ 	if (p->name != NULL)
+ 		foreach(lc, list)
+ 		{
+ 			FunctionParameter *p2 = (FunctionParameter *) lfirst(lc);
+ 			
+ 			if (p->mode == FUNC_PARAM_IN && (p2->mode == FUNC_PARAM_OUT ||
+ 							    p2->mode == FUNC_PARAM_TABLE))
+ 				continue;
+ 			
+ 			if (p->mode == FUNC_PARAM_OUT && (p2->mode == FUNC_PARAM_IN ||
+ 							    p2->mode == FUNC_PARAM_VARIADIC))
+ 				continue;
+ 							    
+ 			if (p2->name != NULL && strcmp(p->name, p2->name) == 0)
+ 				ereport(ERROR, 
+ 						(errcode(ERRCODE_SYNTAX_ERROR),
+ 						 errmsg("parameter has non-unique name"),
+ 						  parser_errposition(location)));
+ 		}
+ 	
+ 	return lappend(list, p);
+ }
+ 
+ /*
   * Must undefine base_yylex before including scan.c, since we want it
   * to create the function base_yylex not filtered_base_yylex.
   */
*** ./src/backend/parser/parse_expr.c.orig	2009-10-02 11:09:53.006291862 +0200
--- ./src/backend/parser/parse_expr.c	2009-10-02 11:10:41.031289311 +0200
***************
*** 255,260 ****
--- 255,269 ----
  		case T_XmlSerialize:
  			result = transformXmlSerialize(pstate, (XmlSerialize *) expr);
  			break;
+ 			
+ 		case T_NamedArgExpr:
+ 			{
+ 				NamedArgExpr *n = (NamedArgExpr *) expr;
+ 				
+ 				n->arg = (Expr *) transformExpr(pstate, (Node *) n->arg);
+ 				result = expr;
+ 				break;
+ 			}
  
  		case T_NullTest:
  			{
*** ./src/backend/parser/parse_func.c.orig	2009-10-02 11:09:53.020292459 +0200
--- ./src/backend/parser/parse_func.c	2009-10-02 15:41:52.163310884 +0200
***************
*** 75,80 ****
--- 75,82 ----
  	bool		retset;
  	int			nvargs;
  	FuncDetailCode fdresult;
+ 	CallNotationType	notation = CALL_NOTATION_POSITIONAL;		/* keep compiler quiet */
+ 	List			*fargnames;
  
  	/*
  	 * Most of the rest of the parser just assumes that functions do not have
***************
*** 123,128 ****
--- 125,188 ----
  		Assert(first_arg != NULL);
  	}
  
+ 	/* Identify call notation, check it and param name uniqueness. */
+ 	fargnames = NIL;
+ 	foreach (l, fargs)
+ 	{
+ 		Node   *arg = lfirst(l);
+ 		ListCell	*lc;
+ 		
+ 		if (IsA(arg, NamedArgExpr))
+ 		{
+ 			NamedArgExpr *n = (NamedArgExpr *) arg;
+ 			
+ 			/* n->name is valid pointer to non empty string */
+ 			Assert(n->name != NULL);
+ 			Assert(*n->name != '\0');
+ 			
+ 			/* 
+ 			 * There are not difference in processing between
+ 			 * mixed and named notation - mixed notation is processed
+ 			 * like named notation, so it is marked as named notation
+ 			 * too.
+ 			 */
+ 			notation = CALL_NOTATION_NAMED;
+ 			
+ 			/* Check duplicates */
+ 			for_each_cell(lc, lnext(l))
+ 			{
+ 				if (IsA(lfirst(lc), NamedArgExpr))
+ 				{
+ 					char	*next_name = ((NamedArgExpr *) lfirst(lc))->name;
+ 					
+ 					Assert(next_name != NULL);
+ 					if (strcmp(n->name, next_name) == 0)
+ 						ereport(ERROR,
+ 								(errcode(ERRCODE_SYNTAX_ERROR),
+ 								 errmsg("named argument has non-unique name"),
+ 								 errhint("Check your named parameters for ambiguous argument names."),
+ 								 parser_errposition(pstate, exprLocation((Node *) lfirst(lc)))));
+ 				}
+ 			}
+ 			fargnames = lappend(fargnames, n->name);
+ 		}
+ 		else
+ 		{
+ 			if (notation != CALL_NOTATION_POSITIONAL)
+ 				ereport(ERROR, 
+ 						(errcode(ERRCODE_SYNTAX_ERROR),
+ 						 errmsg("expected named argument"),
+ 						 errhint("You can't put positional arguments after named arguments."),
+ 						 parser_errposition(pstate, exprLocation(arg))));
+ 			
+ 			fargnames = lappend(fargnames, NULL);
+ 		}
+ 	} 
+ 	
+ 	/* forget argnames list of empty strings when positional notation */
+ 	if (notation == CALL_NOTATION_POSITIONAL)
+ 		fargnames = NIL; 
+ 
  	/*
  	 * Check for column projection: if function has one argument, and that
  	 * argument is of complex type, and function name is not qualified, then
***************
*** 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];
  
--- 190,196 ----
  	 * wasn't any aggregate or variadic decoration.
  	 */
  	if (nargs == 1 && !agg_star && !agg_distinct && over == NULL &&
! 		!func_variadic && list_length(funcname) == 1 && notation == CALL_NOTATION_POSITIONAL)
  	{
  		Oid			argtype = actual_arg_types[0];
  
***************
*** 161,167 ****
  	 * 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);
--- 221,227 ----
  	 * 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, fargnames, nargs, actual_arg_types,
  							   !func_variadic, true,
  							   &funcid, &rettype, &retset, &nvargs,
  							   &declared_arg_types, &argdefaults);
***************
*** 320,325 ****
--- 380,386 ----
  		funcexpr->funcretset = retset;
  		funcexpr->funcformat = COERCE_EXPLICIT_CALL;
  		funcexpr->args = fargs;
+ 		funcexpr->notation = notation;
  		funcexpr->location = location;
  
  		retval = (Node *) funcexpr;
***************
*** 809,814 ****
--- 870,876 ----
  FuncDetailCode
  func_get_detail(List *funcname,
  				List *fargs,
+ 				List *fargnames,
  				int nargs,
  				Oid *argtypes,
  				bool expand_variadic,
***************
*** 833,841 ****
  		*argdefaults = NIL;
  
  	/* Get list of possible candidates from namespace search */
! 	raw_candidates = FuncnameGetCandidates(funcname, nargs,
  										   expand_variadic, expand_defaults);
  
  	/*
  	 * Quickly check if there is an exact match to the input datatypes (there
  	 * can be only one)
--- 895,922 ----
  		*argdefaults = NIL;
  
  	/* Get list of possible candidates from namespace search */
! 	raw_candidates = FuncnameGetCandidates(funcname, nargs, fargnames,
  										   expand_variadic, expand_defaults);
  
+ 	/* Adjust args to order specified by arg names */
+ 	if (fargnames != NIL)
+ 	{
+ 		for (best_candidate = raw_candidates;
+ 			best_candidate != NULL;
+ 			best_candidate = best_candidate->next)
+ 		{
+ 			Oid proargtypes[FUNC_MAX_ARGS];
+ 			int *proargidxs = best_candidate->proargidxs;
+ 			int	i;
+ 
+ 			Assert(proargidxs != NULL);
+ 
+ 			memcpy(proargtypes, best_candidate->args, best_candidate->nargs * sizeof(Oid));
+ 			for (i = 0; i < nargs; i++)
+ 				best_candidate->args[i] = proargtypes[proargidxs[i]];
+ 		}
+ 	}
+ 
  	/*
  	 * Quickly check if there is an exact match to the input datatypes (there
  	 * can be only one)
***************
*** 978,983 ****
--- 1059,1078 ----
  		*nvargs = best_candidate->nvargs;
  		*true_typeids = best_candidate->args;
  
+ 		/* Append positions to NamedArgExpr nodes */
+ 		if (best_candidate->proargidxs != NULL)
+ 		{
+ 			int	i = 0;
+ 			ListCell   *lc;
+ 
+ 			foreach (lc, fargs)
+ 			{
+ 				if (IsA(lfirst(lc), NamedArgExpr))
+ 					((NamedArgExpr *) lfirst(lc))->position = best_candidate->proargidxs[i];
+ 				i++;
+ 			}
+ 		}
+ 
  		ftup = SearchSysCache(PROCOID,
  							  ObjectIdGetDatum(best_candidate->oid),
  							  0, 0, 0);
***************
*** 1010,1020 ****
  				defaults = (List *) stringToNode(str);
  				Assert(IsA(defaults, List));
  				pfree(str);
! 				/* Delete any unused defaults from the returned list */
! 				ndelete = list_length(defaults) - best_candidate->ndargs;
! 				while (ndelete-- > 0)
! 					defaults = list_delete_first(defaults);
! 				*argdefaults = defaults;
  			}
  			else
  				*argdefaults = NIL;
--- 1105,1168 ----
  				defaults = (List *) stringToNode(str);
  				Assert(IsA(defaults, List));
  				pfree(str);
! 				
! 				/* Delete any unused defaults from returned list */
! 				if (best_candidate->proargidxs != NULL)
! 				{
! 					/* Defaults for named notation */
! 					Bitmapset   *argidxs;
! 					ListCell  *lc;
! 					List		*ndefaults;
! 					int	i;
! 					int		firstdefpos;
! 					int		ndargs;
! 					
! 					argidxs = NULL;
! 					i = 0;
! 					foreach(lc, fargs)
! 					{
! 						Node *node = lfirst(lc);
! 						
! 						if (!IsA((Node *) node, NamedArgExpr))
! 						{
! 							argidxs = bms_add_member(argidxs, i);
! 							i++;
! 						}
! 						else
! 							argidxs = bms_add_member(argidxs, ((NamedArgExpr *) node)->position);
! 					}
! 					
! 					/* 
! 					 * Drop unused defaults (overwritten by positional or named parameters).
! 					 * In this moment we don't need to respect real pgproc order, because 
! 					 * these values (argdefaults and true_typeids) are used only for type coercion 
! 					 * They are appended to real parameter list.
! 					 */
! 					ndargs = 0;
! 					ndefaults = NIL;
! 					firstdefpos = pform->pronargs - pform->pronargdefaults;
! 					for (i = 0; i < pform->pronargs; i++)
! 					{
! 						if (!bms_is_member(i, argidxs))
! 						{
! 							ndefaults = lappend(ndefaults, list_nth(defaults, i - firstdefpos));
! 							(*true_typeids)[nargs + ndargs++] = pform->proargtypes.values[i];
! 						}
! 					}
! 					
! 					Assert(ndargs == best_candidate->ndargs);
! 					
! 					bms_free(argidxs);
! 					*argdefaults = ndefaults;
! 				}
! 				else
! 				{
! 					/* Defaults for positional notation */
! 					ndelete = list_length(defaults) - best_candidate->ndargs;
! 					while (ndelete-- > 0)
! 						defaults = list_delete_first(defaults);
! 					*argdefaults = defaults;
! 				}
  			}
  			else
  				*argdefaults = NIL;
***************
*** 1060,1075 ****
  		/* types don't match? then force coercion using a function call... */
  		if (actual_arg_types[i] != declared_arg_types[i])
  		{
! 			lfirst(current_fargs) = coerce_type(pstate,
! 												lfirst(current_fargs),
  												actual_arg_types[i],
  												declared_arg_types[i], -1,
  												COERCION_IMPLICIT,
  												COERCE_IMPLICIT_CAST,
  												-1);
! 		}
  		i++;
! 	}
  }
  
  /*
--- 1208,1253 ----
  		/* types don't match? then force coercion using a function call... */
  		if (actual_arg_types[i] != declared_arg_types[i])
  		{
! 			Node *node = (Node *) lfirst(current_fargs);
! 			Node *result;
! 			NamedArgExpr *namedarg = NULL;
! 			
! 			/* 
! 			 * Extract expr node from NamedArgExpr - don't add new complexity 
! 			 * to coerce_type func - don't enhance coerce_type for envelope 
! 			 * nodes.
! 			 */ 
! 			if (IsA(node, NamedArgExpr))
! 			{
! 				namedarg = (NamedArgExpr *) node;
! 				node = (Node *) namedarg->arg;
! 			}
! 			
! 			result = coerce_type(pstate,
! 												node,
  												actual_arg_types[i],
  												declared_arg_types[i], -1,
  												COERCION_IMPLICIT,
  												COERCE_IMPLICIT_CAST,
  												-1);
! 												
! 			/* When original node was NamedArgExpr, pack result to named expr again. */
! 			if (namedarg != NULL)
! 			{
! 				NamedArgExpr *newarg = (NamedArgExpr *) makeNode(NamedArgExpr);
! 				
! 				newarg->name = namedarg->name;
! 				newarg->arg = (Expr *) result;
! 				newarg->position = namedarg->position;
! 				newarg->location = namedarg->location;
! 				
! 				result = (Node *) newarg;
! 			}
! 			
! 			lfirst(current_fargs) = result;
! 		}		
  		i++;
! 	}	
  }
  
  /*
***************
*** 1276,1282 ****
  {
  	FuncCandidateList clist;
  
! 	clist = FuncnameGetCandidates(funcname, nargs, false, false);
  
  	while (clist)
  	{
--- 1454,1460 ----
  {
  	FuncCandidateList clist;
  
! 	clist = FuncnameGetCandidates(funcname, nargs, NIL, false, false);
  
  	while (clist)
  	{
*** ./src/backend/utils/adt/regproc.c.orig	2009-10-02 11:09:53.032288094 +0200
--- ./src/backend/utils/adt/regproc.c	2009-10-02 11:10:41.034289027 +0200
***************
*** 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,
***************
*** 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;
***************
*** 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)
  	{
*** ./src/backend/utils/adt/ruleutils.c.orig	2009-10-02 11:09:53.046402067 +0200
--- ./src/backend/utils/adt/ruleutils.c	2009-10-02 11:10:41.036288885 +0200
***************
*** 4323,4328 ****
--- 4323,4338 ----
  		case T_FuncExpr:
  			get_func_expr((FuncExpr *) node, context, showimplicit);
  			break;
+ 			
+ 		case T_NamedArgExpr:
+ 			{
+ 				NamedArgExpr *expr = (NamedArgExpr *) node;
+ 				
+ 				get_rule_expr((Node *) expr->arg, context, true);
+ 				appendStringInfo(buf, " AS ");
+ 				appendStringInfo(buf, expr->name);
+ 			}
+ 			break;
  
  		case T_OpExpr:
  			get_oper_expr((OpExpr *) node, context);
***************
*** 6374,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 ||
--- 6384,6390 ----
  	 * 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);
  	if ((p_result == FUNCDETAIL_NORMAL ||
*** ./src/include/catalog/namespace.h.orig	2009-10-02 11:09:53.047289182 +0200
--- ./src/include/catalog/namespace.h	2009-10-02 11:10:41.038290557 +0200
***************
*** 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 */
+ 	int			*proargidxs;		/* array of argument's index in proargs */
  	Oid			args[1];		/* arg types --- VARIABLE LENGTH ARRAY */
  }	*FuncCandidateList;	/* VARIABLE LENGTH STRUCT */
  
***************
*** 54,60 ****
  extern Oid	TypenameGetTypid(const char *typname);
  extern bool TypeIsVisible(Oid typid);
  
! extern FuncCandidateList FuncnameGetCandidates(List *names, int nargs,
  					  bool expand_variadic,
  					  bool expand_defaults);
  extern bool FunctionIsVisible(Oid funcid);
--- 55,61 ----
  extern Oid	TypenameGetTypid(const char *typname);
  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);
*** ./src/include/nodes/nodes.h.orig	2009-10-02 11:09:53.049291212 +0200
--- ./src/include/nodes/nodes.h	2009-10-02 11:10:41.039288671 +0200
***************
*** 123,128 ****
--- 123,129 ----
  	T_WindowFunc,
  	T_ArrayRef,
  	T_FuncExpr,
+ 	T_NamedArgExpr,
  	T_OpExpr,
  	T_DistinctExpr,
  	T_ScalarArrayOpExpr,
*** ./src/include/nodes/parsenodes.h.orig	2009-10-02 11:09:53.050289190 +0200
--- ./src/include/nodes/parsenodes.h	2009-10-02 11:10:41.040288879 +0200
***************
*** 273,279 ****
  {
  	NodeTag		type;
  	List	   *funcname;		/* qualified name of function */
! 	List	   *args;			/* the arguments (list of exprs) */
  	bool		agg_star;		/* argument was really '*' */
  	bool		agg_distinct;	/* arguments were labeled DISTINCT */
  	bool		func_variadic;	/* last argument was labeled VARIADIC */
--- 273,279 ----
  {
  	NodeTag		type;
  	List	   *funcname;		/* qualified name of function */
! 	List	   *args;			/* the arguments (list of FuncCallArg) */
  	bool		agg_star;		/* argument was really '*' */
  	bool		agg_distinct;	/* arguments were labeled DISTINCT */
  	bool		func_variadic;	/* last argument was labeled VARIADIC */
*** ./src/include/nodes/primnodes.h.orig	2009-10-02 11:09:53.051290939 +0200
--- ./src/include/nodes/primnodes.h	2009-10-02 15:42:29.213472437 +0200
***************
*** 300,305 ****
--- 300,314 ----
  } CoercionForm;
  
  /*
+  * CallNotationType - what call notation is used
+  */
+ typedef enum CallNotationType
+ {
+ 	CALL_NOTATION_POSITIONAL,
+ 	CALL_NOTATION_NAMED
+ } CallNotationType;
+ 
+ /*
   * FuncExpr - expression node for a function call
   */
  typedef struct FuncExpr
***************
*** 309,319 ****
--- 318,347 ----
  	Oid			funcresulttype; /* PG_TYPE OID of result value */
  	bool		funcretset;		/* true if function returns set */
  	CoercionForm funcformat;	/* how to display this function call */
+ 	CallNotationType	notation;	/* call notation type */
  	List	   *args;			/* arguments to the function */
  	int			location;		/* token location, or -1 if unknown */
  } FuncExpr;
  
  /*
+  * NamedArgExpr - an named argument of function
+  *
+  * Used when argument has name. When positional notation is used, then
+  * args list doesn't contain any NamedArgExpr. When named notation is
+  * used, all arguments in list are NamedArgExpr. When mixed notation
+  * is used, the first n arguments are Exprs and last m arguments are
+  * NamedArgExpr.
+  */
+ typedef struct NamedArgExpr
+ {
+ 	Expr		xpr;
+ 	Expr	    *arg;		/* the argument */
+ 	char	    *name;		/* an name of argument */
+ 	int	    position;		/* position of argument in proarg list */
+ 	int			location;		/* token location, or -1 if unknown */
+ } NamedArgExpr;
+ 
+ /*
   * OpExpr - expression node for an operator invocation
   *
   * Semantically, this is essentially the same as a function call.
*** ./src/include/parser/parse_func.h.orig	2009-10-02 11:09:53.053289129 +0200
--- ./src/include/parser/parse_func.h	2009-10-02 11:10:41.042289085 +0200
***************
*** 47,53 ****
  				  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,
--- 47,53 ----
  				  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, List *fargnames,
  				int nargs, Oid *argtypes,
  				bool expand_variadic, bool expand_defaults,
  				Oid *funcid, Oid *rettype,
*** ./src/test/regress/expected/create_view.out.orig	2009-10-02 11:09:53.054290947 +0200
--- ./src/test/regress/expected/create_view.out	2009-10-02 11:10:41.043288805 +0200
***************
*** 282,284 ****
--- 282,319 ----
  drop cascades to view mytempview
  drop cascades to view pubview
  SET search_path to public;
+ -- using a named parameters
+ CREATE FUNCTION nmfunc(a anyelement, b anyelement, flag bool) 
+ RETURNS anyelement AS $$
+   SELECT CASE WHEN $3 THEN $1 ELSE $2 END;
+ $$ LANGUAGE sql;
+ CREATE TABLE nmtest(a int, b int, reverse bool);
+ INSERT INTO nmtest VALUES
+   (10,20, true),
+   (20,10, false);
+   
+ CREATE VIEW nmview AS 
+    SELECT a, b, nmfunc(a,b, reverse as flag)
+       FROM nmtest; 
+       
+ SELECT * FROM nmview;
+  a  | b  | nmfunc 
+ ----+----+--------
+  10 | 20 |     10
+  20 | 10 |     10
+ (2 rows)
+ 
+ \d nmview
+      View "public.nmview"
+  Column |  Type   | Modifiers 
+ --------+---------+-----------
+  a      | integer | 
+  b      | integer | 
+  nmfunc | integer | 
+ View definition:
+  SELECT nmtest.a, nmtest.b, nmfunc(nmtest.a, nmtest.b, nmtest.reverse AS flag) AS nmfunc
+    FROM nmtest;
+ 
+ DROP VIEW nmview;
+ DROP TABLE nmtest;
+ DROP FUNCTION nmfunc(anyelement, anyelement, bool);
*** ./src/test/regress/expected/polymorphism.out.orig	2009-10-02 11:09:53.056289067 +0200
--- ./src/test/regress/expected/polymorphism.out	2009-10-02 11:10:41.045289151 +0200
***************
*** 837,843 ****
  
  -- verify it lists properly
  \df dfunc
!                                        List of functions
   Schema | Name  | Result data type |                    Argument data types                    |  Type  
  --------+-------+------------------+-----------------------------------------------------------+--------
   public | dfunc | integer          | a integer DEFAULT 1, OUT sum integer, b integer DEFAULT 2 | normal
--- 837,843 ----
  
  -- verify it lists properly
  \df dfunc
!                                            List of functions
   Schema | Name  | Result data type |                    Argument data types                    |  Type  
  --------+-------+------------------+-----------------------------------------------------------+--------
   public | dfunc | integer          | a integer DEFAULT 1, OUT sum integer, b integer DEFAULT 2 | normal
***************
*** 1005,1011 ****
  ERROR:  cannot remove parameter defaults from existing function
  HINT:  Use DROP FUNCTION first.
  \df dfunc
!                                   List of functions
   Schema | Name  | Result data type |               Argument data types               |  Type  
  --------+-------+------------------+-------------------------------------------------+--------
   public | dfunc | integer          | VARIADIC a integer[] DEFAULT ARRAY[]::integer[] | normal
--- 1005,1011 ----
  ERROR:  cannot remove parameter defaults from existing function
  HINT:  Use DROP FUNCTION first.
  \df dfunc
!                                       List of functions
   Schema | Name  | Result data type |               Argument data types               |  Type  
  --------+-------+------------------+-------------------------------------------------+--------
   public | dfunc | integer          | VARIADIC a integer[] DEFAULT ARRAY[]::integer[] | normal
***************
*** 1038,1040 ****
--- 1038,1273 ----
  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 argument
+ LINE 1: select * from dfunc(10, 20 as b, 30);
+                                          ^
+ HINT:  You can't put positional arguments after named arguments.
+ select * from dfunc(10,10,20 as a); --fail - a overlaps first positional parameter
+ ERROR:  function dfunc(integer, integer, integer) does not exist
+ LINE 1: select * from dfunc(10,10,20 as a);
+                       ^
+ HINT:  No function matches the given name and argument types. You might need to add explicit type casts.
+ drop function dfunc(int, int, int, int);
+ -- test multitypes named params
+ create function dfunc(a varchar, b numeric, c date) returns table (a varchar, b numeric, c date) as $$
+   select $1, $2, $3;
+ $$ language sql;
+ select (dfunc('Hello World',20, to_date('2009-07-25','YYYY-MM-DD'))).*;
+       a      | b  |     c      
+ -------------+----+------------
+  Hello World | 20 | 07-25-2009
+ (1 row)
+ 
+ select * from dfunc('Hello World',20, to_date('2009-07-25','YYYY-MM-DD'));
+       a      | b  |     c      
+ -------------+----+------------
+  Hello World | 20 | 07-25-2009
+ (1 row)
+ 
+ select * from dfunc(to_date('2009-07-25','YYYY-MM-DD') as c, 'Hello World' as a, 20 as b);
+       a      | b  |     c      
+ -------------+----+------------
+  Hello World | 20 | 07-25-2009
+ (1 row)
+ 
+ select * from dfunc('Hello World', 20 as b, to_date('2009-07-25','YYYY-MM-DD') as c);
+       a      | b  |     c      
+ -------------+----+------------
+  Hello World | 20 | 07-25-2009
+ (1 row)
+ 
+ select * from dfunc('Hello World', to_date('2009-07-25','YYYY-MM-DD') as c, 20 as b);
+       a      | b  |     c      
+ -------------+----+------------
+  Hello World | 20 | 07-25-2009
+ (1 row)
+ 
+ select * from dfunc('Hello World', to_date('2009-07-25','YYYY-MM-DD') as c, 20::int as b);
+       a      | b  |     c      
+ -------------+----+------------
+  Hello World | 20 | 07-25-2009
+ (1 row)
+ 
+ drop function dfunc(varchar, numeric, date);
+ -- test, out parameters and named params
+ create function dfunc(a varchar = 'def a', out _a varchar, c numeric = NULL, out _c numeric)
+ returns record as $$
+   select $1, $2;
+ $$ language sql;
+ select (dfunc()).*;
+   _a   | _c 
+ -------+----
+  def a |   
+ (1 row)
+ 
+ select * from dfunc();
+   _a   | _c 
+ -------+----
+  def a |   
+ (1 row)
+ 
+ select * from dfunc('Hello', 100);
+   _a   | _c  
+ -------+-----
+  Hello | 100
+ (1 row)
+ 
+ select * from dfunc('Hello' as a, 100 as c);
+   _a   | _c  
+ -------+-----
+  Hello | 100
+ (1 row)
+ 
+ select * from dfunc(100 as c, 'Hello' as a);
+   _a   | _c  
+ -------+-----
+  Hello | 100
+ (1 row)
+ 
+ select * from dfunc('Hello');
+   _a   | _c 
+ -------+----
+  Hello |   
+ (1 row)
+ 
+ select * from dfunc('Hello', 100 as c);
+   _a   | _c  
+ -------+-----
+  Hello | 100
+ (1 row)
+ 
+ select * from dfunc(100 as c);
+   _a   | _c  
+ -------+-----
+  def a | 100
+ (1 row)
+ 
+ drop function dfunc(varchar, numeric);
+ -- test polymorphic params
+ create function dfunc(a anyelement, b anyelement, flag bool = true)
+ returns anyelement as $$
+   select case when $3 then $1 else $2 end;
+ $$ language sql;
+ select dfunc(1,2);
+  dfunc 
+ -------
+      1
+ (1 row)
+ 
+ select dfunc('a'::text, 'b'); -- positional notation with default
+  dfunc 
+ -------
+  a
+ (1 row)
+ 
+ select dfunc(1 as a, 1 as b);
+  dfunc 
+ -------
+      1
+ (1 row)
+ 
+ select dfunc('a'::text as a, 'b' as b);
+  dfunc 
+ -------
+  a
+ (1 row)
+ 
+ select dfunc('a'::text as a, 'b' as b, false as flag); -- named notation
+  dfunc 
+ -------
+  b
+ (1 row)
+ 
+ select dfunc('b'::text as b, 'a' as a); -- named notation with default
+  dfunc 
+ -------
+  a
+ (1 row)
+ 
+ select dfunc('b'::text as b, 'a' as a, true as flag); -- named notation
+  dfunc 
+ -------
+  a
+ (1 row)
+ 
+ select dfunc('a'::text, 'b', false); -- full positional notation
+  dfunc 
+ -------
+  b
+ (1 row)
+ 
+ select dfunc('a'::text, 'b', false as flag); -- mixed notation
+  dfunc 
+ -------
+  b
+ (1 row)
+ 
+ select dfunc('a'::text, 'b', true); -- full positional notation
+  dfunc 
+ -------
+  a
+ (1 row)
+ 
+ select dfunc('a'::text, 'b', true as flag); -- mixed notation
+  dfunc 
+ -------
+  a
+ (1 row)
+ 
*** ./src/test/regress/expected/rangefuncs.out.orig	2009-10-02 11:09:53.057291374 +0200
--- ./src/test/regress/expected/rangefuncs.out	2009-10-02 15:43:34.972596742 +0200
***************
*** 515,520 ****
--- 515,526 ----
   xyz | {xyz,xyz}
  (1 row)
  
+ -- fails, an rename first argument
+ CREATE OR REPLACE FUNCTION dup (inout f2 anyelement, out f3 anyarray)
+ AS 'select $1, array[$1,$1]' LANGUAGE sql;
+ ERROR:  cannot change name of existing input parameter
+ HINT:  Use DROP FUNCTION first.
+ DROP FUNCTION dup(anyelement);
  -- equivalent specification
  CREATE OR REPLACE FUNCTION dup (inout f2 anyelement, out f3 anyarray)
  AS 'select $1, array[$1,$1]' LANGUAGE sql;
***************
*** 830,832 ****
--- 836,872 ----
  LINE 1: select * from testfoo();
                        ^
  drop function testfoo();
+ --fail, named parameter are not unique
+ create function testfoo(a int, a int) returns int as $$ select 1;$$ language sql;
+ ERROR:  parameter has non-unique name
+ LINE 1: create function testfoo(a int, a int) returns int as $$ sele...
+                                        ^
+ create function testfoo(int, out a int, out a int) returns int as $$ select 1;$$ language sql;
+ ERROR:  parameter has non-unique name
+ LINE 1: create function testfoo(int, out a int, out a int) returns i...
+                                                 ^
+ create function testfoo(out a int, inout a int) returns int as $$ select 1;$$ language sql;
+ ERROR:  parameter has non-unique name
+ LINE 1: create function testfoo(out a int, inout a int) returns int ...
+                                            ^
+ create function testfoo(a int, inout a int) returns int as $$ select 1;$$ language sql; 
+ ERROR:  parameter has non-unique name
+ LINE 1: create function testfoo(a int, inout a int) returns int as $...
+                                        ^
+ -- valid
+ create function testfoo(a int, out a int) returns int as $$ select $1;$$ language sql;
+ select testfoo(37);
+  testfoo 
+ ---------
+       37
+ (1 row)
+ 
+ drop function testfoo(int);
+ create function testfoo(a int) returns table(a int) as $$ select $1;$$ language sql;
+ select * from testfoo(37);
+  a  
+ ----
+  37
+ (1 row)
+ 
+ drop function testfoo(int);
*** ./src/test/regress/sql/create_view.sql.orig	2009-10-02 11:09:53.058289003 +0200
--- ./src/test/regress/sql/create_view.sql	2009-10-02 11:10:41.046288940 +0200
***************
*** 195,197 ****
--- 195,221 ----
  DROP SCHEMA testviewschm2 CASCADE;
  
  SET search_path to public;
+ 
+ -- using a named parameters
+ CREATE FUNCTION nmfunc(a anyelement, b anyelement, flag bool) 
+ RETURNS anyelement AS $$
+   SELECT CASE WHEN $3 THEN $1 ELSE $2 END;
+ $$ LANGUAGE sql;
+ 
+ CREATE TABLE nmtest(a int, b int, reverse bool);
+ INSERT INTO nmtest VALUES
+   (10,20, true),
+   (20,10, false);
+   
+ CREATE VIEW nmview AS 
+    SELECT a, b, nmfunc(a,b, reverse as flag)
+       FROM nmtest; 
+       
+ SELECT * FROM nmview;
+ 
+ \d nmview
+ 
+ DROP VIEW nmview;
+ DROP TABLE nmtest;
+ DROP FUNCTION nmfunc(anyelement, anyelement, bool);
+ 
*** ./src/test/regress/sql/polymorphism.sql.orig	2009-10-02 11:09:53.060291382 +0200
--- ./src/test/regress/sql/polymorphism.sql	2009-10-02 11:10:41.047289148 +0200
***************
*** 624,626 ****
--- 624,702 ----
  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);
+ 
+ -- test multitypes named params
+ create function dfunc(a varchar, b numeric, c date) returns table (a varchar, b numeric, c date) as $$
+   select $1, $2, $3;
+ $$ language sql;
+ 
+ select (dfunc('Hello World',20, to_date('2009-07-25','YYYY-MM-DD'))).*;
+ select * from dfunc('Hello World',20, to_date('2009-07-25','YYYY-MM-DD'));
+ select * from dfunc(to_date('2009-07-25','YYYY-MM-DD') as c, 'Hello World' as a, 20 as b);
+ select * from dfunc('Hello World', 20 as b, to_date('2009-07-25','YYYY-MM-DD') as c);
+ select * from dfunc('Hello World', to_date('2009-07-25','YYYY-MM-DD') as c, 20 as b);
+ select * from dfunc('Hello World', to_date('2009-07-25','YYYY-MM-DD') as c, 20::int as b);
+ 
+ drop function dfunc(varchar, numeric, date);
+ 
+ -- test, out parameters and named params
+ create function dfunc(a varchar = 'def a', out _a varchar, c numeric = NULL, out _c numeric)
+ returns record as $$
+   select $1, $2;
+ $$ language sql;
+ 
+ select (dfunc()).*;
+ select * from dfunc();
+ select * from dfunc('Hello', 100);
+ select * from dfunc('Hello' as a, 100 as c);
+ select * from dfunc(100 as c, 'Hello' as a);
+ select * from dfunc('Hello');
+ select * from dfunc('Hello', 100 as c);
+ select * from dfunc(100 as c);
+ 
+ drop function dfunc(varchar, numeric);
+ 
+ -- test polymorphic params
+ create function dfunc(a anyelement, b anyelement, flag bool = true)
+ returns anyelement as $$
+   select case when $3 then $1 else $2 end;
+ $$ language sql;
+ 
+ select dfunc(1,2);
+ select dfunc('a'::text, 'b'); -- positional notation with default
+ 
+ select dfunc(1 as a, 1 as b);
+ select dfunc('a'::text as a, 'b' as b);
+ select dfunc('a'::text as a, 'b' as b, false as flag); -- named notation
+ 
+ select dfunc('b'::text as b, 'a' as a); -- named notation with default
+ select dfunc('b'::text as b, 'a' as a, true as flag); -- named notation
+ 
+ select dfunc('a'::text, 'b', false); -- full positional notation
+ select dfunc('a'::text, 'b', false as flag); -- mixed notation
+ select dfunc('a'::text, 'b', true); -- full positional notation
+ select dfunc('a'::text, 'b', true as flag); -- mixed notation
*** ./src/test/regress/sql/rangefuncs.sql.orig	2009-10-02 11:09:53.061289011 +0200
--- ./src/test/regress/sql/rangefuncs.sql	2009-10-02 11:10:41.048291101 +0200
***************
*** 251,256 ****
--- 251,262 ----
  SELECT dup('xyz'::text);
  SELECT * FROM dup('xyz'::text);
  
+ -- fails, an rename first argument
+ CREATE OR REPLACE FUNCTION dup (inout f2 anyelement, out f3 anyarray)
+ AS 'select $1, array[$1,$1]' LANGUAGE sql;
+ 
+ DROP FUNCTION dup(anyelement);
+ 
  -- equivalent specification
  CREATE OR REPLACE FUNCTION dup (inout f2 anyelement, out f3 anyarray)
  AS 'select $1, array[$1,$1]' LANGUAGE sql;
***************
*** 385,387 ****
--- 391,408 ----
  select * from testfoo(); -- fail
  
  drop function testfoo();
+ 
+ --fail, named parameter are not unique
+ create function testfoo(a int, a int) returns int as $$ select 1;$$ language sql;
+ create function testfoo(int, out a int, out a int) returns int as $$ select 1;$$ language sql;
+ create function testfoo(out a int, inout a int) returns int as $$ select 1;$$ language sql;
+ create function testfoo(a int, inout a int) returns int as $$ select 1;$$ language sql; 
+ 
+ -- valid
+ create function testfoo(a int, out a int) returns int as $$ select $1;$$ language sql;
+ select testfoo(37);
+ drop function testfoo(int);
+ create function testfoo(a int) returns table(a int) as $$ select $1;$$ language sql;
+ select * from testfoo(37);
+ drop function testfoo(int);
+ 
