Issues for named/mixed function notation patch

Started by Tom Laneover 16 years ago59 messages
#1Tom Lane
tgl@sss.pgh.pa.us

I've now read most of this patch, and I think there are some things that
need rework, and perhaps debate about what we want.

1. As I already mentioned, I think the mixed-notation business is a bad
idea. It's unintuitive, it's not especially useful, and it substantially
increases our risk of being semantically incompatible with whatever the
SQL committee might someday do in this area. I think we should disallow
it until we see what they do. I gather that this might be an unpopular
position though.

2. It doesn't appear that any attention has been given to what happens
if CREATE OR REPLACE FUNCTION is used to change the parameter names of
an existing function. Since the post-analysis representation of parameter
lists is still entirely positional, the actual effect on a function call
in a stored view or rule is nil --- it will still call the same function
it did before, passing the parameters that were originally identified to
be passed. That might be considered good, but it's quite unlike what
will happen to function calls that are stored textually (eg, in plpgsql
functions). Is that what we want? Or should we consider that parameter
names are now part of the API of a function, and forbid CREATE OR REPLACE
FUNCTION from changing them? Or perhaps we should recheck parameter name
matching someplace after analysis, perhaps at default-expansion time?

3. In the same vein, CREATE FUNCTION doesn't disallow duplicate parameter
names, nor functions that have names for some but not all parameters.
The patch appears to cope with the latter case but not the former.
Should we disallow these things in CREATE FUNCTION, or make the patch
never match such functions, or what?

4. No attention has been given to making ruleutils.c list out named or
mixed function calls correctly.

5. I don't like anything about the "leaky list" representation of
analyzed function arguments. Having null subexpressions in unexpected
places isn't a good idea --- it's likely to cause crashes in code that
isn't being really cautious. Moreover, if we did ultimately support
mixed notation, there's no way to list it out correctly on the basis
of this representation, because you can't tell which arguments were
named and which weren't. I think it would be better to keep the
ArgExprs in the transformed parameter list and have the planner
remove them (and reorder the arguments if needed) when it does
default-argument expansion. Depending on what you think about point
#2, the transformed ArgExprs might need to carry the argument number
instead of the argument name, but in any case they'd just be there
for named arguments. This approach probably will also reduce the
amount of change in the parser, since you won't have to separate
the names from the argument list and pass those all over the place
separately.

Some minor style issues:

* ArgExpr is confusingly named and incorrectly documented, since it's
only used for named arguments. Perhaps NamedArgExpr would be better.
Also, it'd probably be a good idea to include a location field in it
(pointing at the parameter name not the argument expression).

* Most of the PG source code just writes "short" or "long",
not "short int". Actually I wonder whether "int2" wouldn't
be preferred anyway, since that's how the relevant pg_proc
columns are declared.

* The error messages aren't even approximately conformant to style guide.

* Please avoid useless whitespace changes, especially ones as
ill-considered as this:

***************
*** 10028,10034 ****
;

! name: ColId { $$ = $1; };

  database_name:
  			ColId									{ $$ = $1; };
--- 10056,10062 ----
  		;

! name: ColId { $$ = $1; };

database_name:
ColId { $$ = $1; };

I'm going to mark the patch Waiting on Author, since it's not close
to being committable until these issues are resolved.

regards, tom lane

#2Tom Lane
tgl@sss.pgh.pa.us
In reply to: Tom Lane (#1)
Re: Issues for named/mixed function notation patch

Oh, another thing: the present restriction that all function parameters
after the first one with a default must also have defaults is based on
limitations of positional call notation. Does it make sense to relax
that restriction once we allow named call notation, and if so what
should we do exactly? (This could be addressed in a followup patch,
it doesn't necessarily have to be dealt with immediately.)

regards, tom lane

#3Greg Stark
gsstark@mit.edu
In reply to: Tom Lane (#1)
Re: Issues for named/mixed function notation patch

On Sun, Aug 9, 2009 at 7:30 PM, Tom Lane<tgl@sss.pgh.pa.us> wrote:

1. As I already mentioned, I think the mixed-notation business is a bad
idea.  It's unintuitive, it's not especially useful, and it substantially
increases our risk of being semantically incompatible with whatever the
SQL committee might someday do in this area.  I think we should disallow
it until we see what they do.  I gather that this might be an unpopular
position though.

It seems like we could safely allow the cases which are unambiguous.
Namely where the call has a sequence of unnamed parameters followed by
some named parameters all of which refer to parameters which come
later.

So foo(1,2,3 as x,4 as y) would be legal as long as x and y were not
one of the first three arguments.

That's a pretty common idiom when you have a function which does
something normal to the first few arguments and then has a bunch of
non-standard modes which can be optionally invoked. Take for example
the perl DBI's connect method which takes a data source, username,
authentication token, then a list of parameters which can be any of
dozens of parameters (actually it takes a fifth argument which is a
hashref -- but the point here is just that it's a common style, not
that we should be copying perl's solution).

The reason I'm saying this is safe is because there's just no other
possible interpretation. As long as it only covers the unambiguous
cases then there's no other meaning other implementations can define
which this would conflict with.

--
greg
http://mit.edu/~gsstark/resume.pdf

#4Robert Haas
robertmhaas@gmail.com
In reply to: Tom Lane (#1)
Re: Issues for named/mixed function notation patch

On Sun, Aug 9, 2009 at 2:30 PM, Tom Lane<tgl@sss.pgh.pa.us> wrote:

I've now read most of this patch, and I think there are some things that
need rework, and perhaps debate about what we want.

1. As I already mentioned, I think the mixed-notation business is a bad
idea.  It's unintuitive, it's not especially useful, and it substantially
increases our risk of being semantically incompatible with whatever the
SQL committee might someday do in this area.  I think we should disallow
it until we see what they do.  I gather that this might be an unpopular
position though.

LOL. I already did my yelling and screaming on this point... though
it's all good-natured, in case that doesn't come through in the email.

2. It doesn't appear that any attention has been given to what happens
if CREATE OR REPLACE FUNCTION is used to change the parameter names of
an existing function.  Since the post-analysis representation of parameter
lists is still entirely positional, the actual effect on a function call
in a stored view or rule is nil --- it will still call the same function
it did before, passing the parameters that were originally identified to
be passed.  That might be considered good, but it's quite unlike what
will happen to function calls that are stored textually (eg, in plpgsql
functions).  Is that what we want?

That sounds pretty dangerous. What if someone renames a parameter so
as to invert its sense, or something? (automatically_delete_all_files
becomes confirm_before_deleting, or somesuch)

Or should we consider that parameter
names are now part of the API of a function, and forbid CREATE OR REPLACE
FUNCTION from changing them?  Or perhaps we should recheck parameter name
matching someplace after analysis, perhaps at default-expansion time?

I'm not sure what the right way to go with this is, but we have to
think about how it plays with function overloading - can I define two
identically-named functions with different sets of positional
parameters, and then resolve the function call based on which
parameters are specified?

3. In the same vein, CREATE FUNCTION doesn't disallow duplicate parameter
names, nor functions that have names for some but not all parameters.
The patch appears to cope with the latter case but not the former.
Should we disallow these things in CREATE FUNCTION, or make the patch
never match such functions, or what?

I think duplicate parameter names shouldn't be allowed.

4. No attention has been given to making ruleutils.c list out named or
mixed function calls correctly.

5. I don't like anything about the "leaky list" representation of
analyzed function arguments.  Having null subexpressions in unexpected
places isn't a good idea --- it's likely to cause crashes in code that
isn't being really cautious.  Moreover, if we did ultimately support
mixed notation, there's no way to list it out correctly on the basis
of this representation, because you can't tell which arguments were
named and which weren't.  I think it would be better to keep the
ArgExprs in the transformed parameter list and have the planner
remove them (and reorder the arguments if needed) when it does
default-argument expansion.  Depending on what you think about point
#2, the transformed ArgExprs might need to carry the argument number
instead of the argument name, but in any case they'd just be there
for named arguments.  This approach probably will also reduce the
amount of change in the parser, since you won't have to separate
the names from the argument list and pass those all over the place
separately.

Some minor style issues:

* ArgExpr is confusingly named and incorrectly documented, since it's
only used for named arguments.  Perhaps NamedArgExpr would be better.
Also, it'd probably be a good idea to include a location field in it
(pointing at the parameter name not the argument expression).

* Most of the PG source code just writes "short" or "long",
not "short int".  Actually I wonder whether "int2" wouldn't
be preferred anyway, since that's how the relevant pg_proc
columns are declared.

* The error messages aren't even approximately conformant to style guide.

* Please avoid useless whitespace changes, especially ones as
ill-considered as this:

***************
*** 10028,10034 ****
               ;

! name:         ColId                                                                   { $$ = $1; };

 database_name:
                       ColId                                                                   { $$ = $1; };
--- 10056,10062 ----
               ;

! name:         ColId                                                           { $$ = $1; };

 database_name:
                       ColId                                                                   { $$ = $1; };

I'm going to mark the patch Waiting on Author, since it's not close
to being committable until these issues are resolved.

Is it realistic to think that this will be finished and committed this week?

...Robert

#5Tom Lane
tgl@sss.pgh.pa.us
In reply to: Robert Haas (#4)
Re: Issues for named/mixed function notation patch

Robert Haas <robertmhaas@gmail.com> writes:

On Sun, Aug 9, 2009 at 2:30 PM, Tom Lane<tgl@sss.pgh.pa.us> wrote:

I'm going to mark the patch Waiting on Author, since it's not close
to being committable until these issues are resolved.

Is it realistic to think that this will be finished and committed this week?

I didn't want to prejudge that question. We still have the rest of the
week, and there's not that much else left to do, at least from my
standpoint (some of the other committers still have stuff on their
plates).

regards, tom lane

#6Robert Haas
robertmhaas@gmail.com
In reply to: Tom Lane (#5)
Re: Issues for named/mixed function notation patch

On Sun, Aug 9, 2009 at 9:36 PM, Tom Lane<tgl@sss.pgh.pa.us> wrote:

Robert Haas <robertmhaas@gmail.com> writes:

On Sun, Aug 9, 2009 at 2:30 PM, Tom Lane<tgl@sss.pgh.pa.us> wrote:

I'm going to mark the patch Waiting on Author, since it's not close
to being committable until these issues are resolved.

Is it realistic to think that this will be finished and committed this week?

I didn't want to prejudge that question.  We still have the rest of the
week, and there's not that much else left to do, at least from my
standpoint (some of the other committers still have stuff on their
plates).

Fair point, my impatience is showing. Sorry.

...Robert

#7Greg Stark
gsstark@mit.edu
In reply to: Robert Haas (#4)
Re: Issues for named/mixed function notation patch

On Mon, Aug 10, 2009 at 2:23 AM, Robert Haas<robertmhaas@gmail.com> wrote:

2. It doesn't appear that any attention has been given to what happens
if CREATE OR REPLACE FUNCTION is used to change the parameter names of
an existing function.  Since the post-analysis representation of parameter
lists is still entirely positional, the actual effect on a function call
in a stored view or rule is nil --- it will still call the same function
it did before, passing the parameters that were originally identified to
be passed.  That might be considered good, but it's quite unlike what
will happen to function calls that are stored textually (eg, in plpgsql
functions).  Is that what we want?

That sounds pretty dangerous.  What if someone renames a parameter so
as to invert its sense, or something?  (automatically_delete_all_files
becomes confirm_before_deleting, or somesuch)

There's also the existing users using positional notation to consider.
If all my callers are using positional notation then I might be kind
of annoyed if I can't fix the parameter names of my functions because
it would change the function signature. That would be a functionality
regression for me.

But on balance I don't see a better solution. If we allow people to
change the parameter names and they're used for named arguments then
it seems like the behaviour is not very clear and predictable no
matter what resolution we pick.

--
greg
http://mit.edu/~gsstark/resume.pdf

#8Pavel Stehule
pavel.stehule@gmail.com
In reply to: Tom Lane (#1)
Re: Issues for named/mixed function notation patch

2009/8/9 Tom Lane <tgl@sss.pgh.pa.us>:

I've now read most of this patch, and I think there are some things that
need rework, and perhaps debate about what we want.

1. As I already mentioned, I think the mixed-notation business is a bad
idea.  It's unintuitive, it's not especially useful, and it substantially
increases our risk of being semantically incompatible with whatever the
SQL committee might someday do in this area.  I think we should disallow
it until we see what they do.  I gather that this might be an unpopular
position though.

I disagree. I thing so people expect mainly mixed notation.

2. It doesn't appear that any attention has been given to what happens
if CREATE OR REPLACE FUNCTION is used to change the parameter names of
an existing function.  Since the post-analysis representation of parameter
lists is still entirely positional, the actual effect on a function call
in a stored view or rule is nil --- it will still call the same function
it did before, passing the parameters that were originally identified to
be passed.  That might be considered good, but it's quite unlike what
will happen to function calls that are stored textually (eg, in plpgsql
functions).  Is that what we want?  Or should we consider that parameter
names are now part of the API of a function, and forbid CREATE OR REPLACE
FUNCTION from changing them?  Or perhaps we should recheck parameter name
matching someplace after analysis, perhaps at default-expansion time?

I can't to imagine some recheck, so I prefer forbid CREATE OR REPLACE
FUNCTION for name change. We should to find some better solution
later. When we immutable names, then we have to have well RENAME
statement in plpgsql.

3. In the same vein, CREATE FUNCTION doesn't disallow duplicate parameter
names, nor functions that have names for some but not all parameters.
The patch appears to cope with the latter case but not the former.
Should we disallow these things in CREATE FUNCTION, or make the patch
never match such functions, or what?

I thing, so duplicate parameter names is clean bug - minimally for
language like plpgsql. I can to imagine some use case in C or plperlu,
but now we have variadic params or arrays, so duplicate names should
be deprecated.

4. No attention has been given to making ruleutils.c list out named or
mixed function calls correctly.

5. I don't like anything about the "leaky list" representation of
analyzed function arguments.  Having null subexpressions in unexpected
places isn't a good idea --- it's likely to cause crashes in code that
isn't being really cautious.  Moreover, if we did ultimately support
mixed notation, there's no way to list it out correctly on the basis
of this representation, because you can't tell which arguments were
named and which weren't.  I think it would be better to keep the
ArgExprs in the transformed parameter list and have the planner
remove them (and reorder the arguments if needed) when it does
default-argument expansion.  Depending on what you think about point
#2, the transformed ArgExprs might need to carry the argument number
instead of the argument name, but in any case they'd just be there
for named arguments.  This approach probably will also reduce the
amount of change in the parser, since you won't have to separate
the names from the argument list and pass those all over the place
separately.

I have to look on this - I newer did some changes in planner, so I
know nothing about it now.

Some minor style issues:

* ArgExpr is confusingly named and incorrectly documented, since it's
only used for named arguments.  Perhaps NamedArgExpr would be better.
Also, it'd probably be a good idea to include a location field in it
(pointing at the parameter name not the argument expression).

ook

* Most of the PG source code just writes "short" or "long",
not "short int".  Actually I wonder whether "int2" wouldn't
be preferred anyway, since that's how the relevant pg_proc
columns are declared.

ok

* The error messages aren't even approximately conformant to style guide.

* Please avoid useless whitespace changes, especially ones as
ill-considered as this:

***************
*** 10028,10034 ****
               ;

! name:         ColId                                                                   { $$ = $1; };

 database_name:
                       ColId                                                                   { $$ = $1; };
--- 10056,10062 ----
               ;

! name:         ColId                                                           { $$ = $1; };

 database_name:
                       ColId                                                                   { $$ = $1; };

I am sorry, I'll be more careful

I'm going to mark the patch Waiting on Author, since it's not close
to being committable until these issues are resolved.

I spend week out of office, and actually I working on house, but I
hope so tomorrow will have time for fixing these issues.

                       regards, tom lane

thank you
Pavel Stehule

#9Pavel Stehule
pavel.stehule@gmail.com
In reply to: Tom Lane (#2)
Re: Issues for named/mixed function notation patch

2009/8/9 Tom Lane <tgl@sss.pgh.pa.us>:

Oh, another thing: the present restriction that all function parameters
after the first one with a default must also have defaults is based on
limitations of positional call notation.  Does it make sense to relax
that restriction once we allow named call notation, and if so what
should we do exactly?  (This could be addressed in a followup patch,
it doesn't necessarily have to be dealt with immediately.)

Yes, this rule should be useless. But with the remove of this rule, we
have to modify algorithm for positional notation. It depends on this
rule.

regards
Pavel Stehule

Show quoted text

                       regards, tom lane

#10Pavel Stehule
pavel.stehule@gmail.com
In reply to: Tom Lane (#1)
1 attachment(s)
Re: Issues for named/mixed function notation patch

Hello,

I reworked patch to respect mentioned issues. - this patch still
implement mixed notation - I am thing so this notation is really
important. All others I respect. The behave is without change, fixed
some bugs, enhanced regress tests.

Sorry for delay.

Regards
Pavel Stehule

p.s. Bernard, please, can you look on this version?

2009/8/9 Tom Lane <tgl@sss.pgh.pa.us>:

Show quoted text

I've now read most of this patch, and I think there are some things that
need rework, and perhaps debate about what we want.

1. As I already mentioned, I think the mixed-notation business is a bad
idea.  It's unintuitive, it's not especially useful, and it substantially
increases our risk of being semantically incompatible with whatever the
SQL committee might someday do in this area.  I think we should disallow
it until we see what they do.  I gather that this might be an unpopular
position though.

2. It doesn't appear that any attention has been given to what happens
if CREATE OR REPLACE FUNCTION is used to change the parameter names of
an existing function.  Since the post-analysis representation of parameter
lists is still entirely positional, the actual effect on a function call
in a stored view or rule is nil --- it will still call the same function
it did before, passing the parameters that were originally identified to
be passed.  That might be considered good, but it's quite unlike what
will happen to function calls that are stored textually (eg, in plpgsql
functions).  Is that what we want?  Or should we consider that parameter
names are now part of the API of a function, and forbid CREATE OR REPLACE
FUNCTION from changing them?  Or perhaps we should recheck parameter name
matching someplace after analysis, perhaps at default-expansion time?

3. In the same vein, CREATE FUNCTION doesn't disallow duplicate parameter
names, nor functions that have names for some but not all parameters.
The patch appears to cope with the latter case but not the former.
Should we disallow these things in CREATE FUNCTION, or make the patch
never match such functions, or what?

4. No attention has been given to making ruleutils.c list out named or
mixed function calls correctly.

5. I don't like anything about the "leaky list" representation of
analyzed function arguments.  Having null subexpressions in unexpected
places isn't a good idea --- it's likely to cause crashes in code that
isn't being really cautious.  Moreover, if we did ultimately support
mixed notation, there's no way to list it out correctly on the basis
of this representation, because you can't tell which arguments were
named and which weren't.  I think it would be better to keep the
ArgExprs in the transformed parameter list and have the planner
remove them (and reorder the arguments if needed) when it does
default-argument expansion.  Depending on what you think about point
#2, the transformed ArgExprs might need to carry the argument number
instead of the argument name, but in any case they'd just be there
for named arguments.  This approach probably will also reduce the
amount of change in the parser, since you won't have to separate
the names from the argument list and pass those all over the place
separately.

Some minor style issues:

* ArgExpr is confusingly named and incorrectly documented, since it's
only used for named arguments.  Perhaps NamedArgExpr would be better.
Also, it'd probably be a good idea to include a location field in it
(pointing at the parameter name not the argument expression).

* Most of the PG source code just writes "short" or "long",
not "short int".  Actually I wonder whether "int2" wouldn't
be preferred anyway, since that's how the relevant pg_proc
columns are declared.

* The error messages aren't even approximately conformant to style guide.

* Please avoid useless whitespace changes, especially ones as
ill-considered as this:

***************
*** 10028,10034 ****
               ;

! name:         ColId                                                                   { $$ = $1; };

 database_name:
                       ColId                                                                   { $$ = $1; };
--- 10056,10062 ----
               ;

! name:         ColId                                                           { $$ = $1; };

 database_name:
                       ColId                                                                   { $$ = $1; };

I'm going to mark the patch Waiting on Author, since it's not close
to being committable until these issues are resolved.

                       regards, tom lane

Attachments:

mnnotation.diff.gzapplication/x-gzip; name=mnnotation.diff.gzDownload
#11Robert Haas
robertmhaas@gmail.com
In reply to: Pavel Stehule (#10)
Re: Issues for named/mixed function notation patch

On Mon, Aug 24, 2009 at 3:19 PM, Pavel Stehule <pavel.stehule@gmail.com> wrote:

I reworked patch to respect mentioned issues. - this patch still
implement mixed notation - I am thing so this notation is really
important. All others I respect. The behave is without change, fixed
some bugs, enhanced regress tests.

This does not compile.

...Robert

#12Pavel Stehule
pavel.stehule@gmail.com
In reply to: Robert Haas (#11)
Re: Issues for named/mixed function notation patch

2009/9/14 Robert Haas <robertmhaas@gmail.com>:

On Mon, Aug 24, 2009 at 3:19 PM, Pavel Stehule <pavel.stehule@gmail.com> wrote:

I reworked patch to respect mentioned issues. - this patch still
implement mixed notation - I am thing so this notation is really
important. All others I respect. The behave is without change, fixed
some bugs, enhanced regress tests.

This does not compile.

I'll recheck it today

Pavel

Show quoted text

...Robert

#13Pavel Stehule
pavel.stehule@gmail.com
In reply to: Robert Haas (#11)
1 attachment(s)
Re: Issues for named/mixed function notation patch

Hello Robert,

2009/9/14 Robert Haas <robertmhaas@gmail.com>:

On Mon, Aug 24, 2009 at 3:19 PM, Pavel Stehule <pavel.stehule@gmail.com> wrote:

I reworked patch to respect mentioned issues. - this patch still
implement mixed notation - I am thing so this notation is really
important. All others I respect. The behave is without change, fixed
some bugs, enhanced regress tests.

This does not compile.

please, can you try this version? I hope so this in commitfest form
too. I didn't do any changes, but it can be broken. I compiled
attached patch today without problems. I have Federa 11. If you will
have a problems still, please, send me log.

Thank You
Pavel

Show quoted text

...Robert

Attachments:

mnnotation.diff.gzapplication/x-gzip; name=mnnotation.diff.gzDownload
#14Robert Haas
robertmhaas@gmail.com
In reply to: Pavel Stehule (#13)
1 attachment(s)
Re: Issues for named/mixed function notation patch

On Mon, Sep 14, 2009 at 6:09 AM, Pavel Stehule <pavel.stehule@gmail.com> wrote:

Hello Robert,

2009/9/14 Robert Haas <robertmhaas@gmail.com>:

On Mon, Aug 24, 2009 at 3:19 PM, Pavel Stehule <pavel.stehule@gmail.com> wrote:

I reworked patch to respect mentioned issues. - this patch still
implement mixed notation - I am thing so this notation is really
important. All others I respect. The behave is without change, fixed
some bugs, enhanced regress tests.

This does not compile.

please, can you try this version? I hope so this in commitfest form
too. I didn't do any changes, but it can be broken. I compiled
attached patch today without problems. I have Federa 11. If you will
have a problems still, please, send me log.

Same problem. Build log attached.

...Robert

Attachments:

typescriptapplication/octet-stream; name=typescriptDownload
#15Pavel Stehule
pavel.stehule@gmail.com
In reply to: Robert Haas (#14)
1 attachment(s)
Re: Issues for named/mixed function notation patch

Same problem.  Build log attached.

...Robert

My renonc, please, try new patch. I forgot mark regproc.c file.

regards
Pavel Stehule

Attachments:

nm.diff.gzapplication/x-gzip; name=nm.diff.gzDownload
#16Robert Haas
robertmhaas@gmail.com
In reply to: Pavel Stehule (#15)
Re: Issues for named/mixed function notation patch

On Tue, Sep 15, 2009 at 4:51 AM, Pavel Stehule <pavel.stehule@gmail.com> wrote:

Same problem.  Build log attached.

...Robert

My renonc, please, try new patch. I forgot mark regproc.c file.

regards
Pavel Stehule

This one compiles for me.

...Robert

#17Jeff Davis
pgsql@j-davis.com
In reply to: Pavel Stehule (#15)
Re: Issues for named/mixed function notation patch

On Tue, 2009-09-15 at 10:51 +0200, Pavel Stehule wrote:

My renonc, please, try new patch. I forgot mark regproc.c file.

I think the documentation around calling functions is disorganized:

Variadic functions, functions with defaults, SRFs, out parameters, and
polymorphism are all explained in 34.4, which is about SQL functions
specifically.

Overloading is in chapter 34 also, but not specifically in the SQL
function section like the rest.

Function calls themselves are only given 5 lines of explanation in
4.2.6, with no mention of things like the VARIADIC keyword.

These complaints aren't about the patch, but we might want to consider
some reorganization of those sections (probably a separate doc patch).

The interaction with variadic functions appears to be misdocumented.

From the code and tests, the VARIADIC keyword appears to be optional

when using named notation, but required when using positional notation.
But the documentation says:

"However, a named variadic argument can only be called the way shown in
the example above. The VARIADIC keyword must not be specified and a
variadic notation of all arguments is not supported. To use variadic
argument lists you must use positional notation instead."

What is the intended behavior? I think we should always require VARIADIC
to be specified regardless of using named notation.

I'm still reviewing the code.

Regards,
Jeff Davis

#18Pavel Stehule
pavel.stehule@gmail.com
In reply to: Jeff Davis (#17)
Re: Issues for named/mixed function notation patch

"However, a named variadic argument can only be called the way shown in
the example above. The VARIADIC keyword must not be specified and a
variadic notation of all arguments is not supported. To use variadic
argument lists you must use positional notation instead."

What is the intended behavior? I think we should always require VARIADIC
to be specified regardless of using named notation.

maybe we could to support variadic named parameters in future - then
using VARIADIC keyword should be necessary - like

foo(10 AS p1, 20 AS p1, 30 AS p3) is equalent of
foo(VARIADIC ARRAY[10,20] AS p1, 30 AS p3)

if we plan this feature, the VARIADIC keyword have to be mandatory.

Regards
Pavel Stehule

Show quoted text

I'm still reviewing the code.

Regards,
       Jeff Davis

#19Robert Haas
robertmhaas@gmail.com
In reply to: Pavel Stehule (#18)
Re: Issues for named/mixed function notation patch

On Sun, Sep 27, 2009 at 12:37 AM, Pavel Stehule <pavel.stehule@gmail.com> wrote:

"However, a named variadic argument can only be called the way shown in
the example above. The VARIADIC keyword must not be specified and a
variadic notation of all arguments is not supported. To use variadic
argument lists you must use positional notation instead."

What is the intended behavior? I think we should always require VARIADIC
to be specified regardless of using named notation.

maybe we could to support variadic named parameters in future - then
using VARIADIC keyword should be necessary - like

foo(10 AS p1, 20 AS p1, 30 AS p3) is equalent of
foo(VARIADIC ARRAY[10,20] AS p1, 30 AS p3)

Pavel,

This doesn't make sense to me, FWIW. I don't think we should allow
parameters to be specified more than once. It's hard for me to
imagine how that could be useful.

I'm still reviewing the code.

Jeff,

When will you be able to post this review?

Thanks,

...Robert

#20Pavel Stehule
pavel.stehule@gmail.com
In reply to: Robert Haas (#19)
Re: Issues for named/mixed function notation patch

2009/9/27 Robert Haas <robertmhaas@gmail.com>:

On Sun, Sep 27, 2009 at 12:37 AM, Pavel Stehule <pavel.stehule@gmail.com> wrote:

"However, a named variadic argument can only be called the way shown in
the example above. The VARIADIC keyword must not be specified and a
variadic notation of all arguments is not supported. To use variadic
argument lists you must use positional notation instead."

What is the intended behavior? I think we should always require VARIADIC
to be specified regardless of using named notation.

maybe we could to support variadic named parameters in future - then
using VARIADIC keyword should be necessary - like

foo(10 AS p1, 20 AS p1, 30 AS p3) is equalent of
foo(VARIADIC ARRAY[10,20] AS p1, 30 AS p3)

Pavel,

This doesn't make sense to me, FWIW.  I don't think we should allow
parameters to be specified more than once.  It's hard for me to
imagine how that could be useful.

ook I thing, so this should be little bit unclean too. I though why we
need VARIADIC keyword mandatory for named notation. When we could
specify only unique names, then we could use only one "packed"
variadic parameter - and then VARIADIC keyword isn't necessary.

Is this idea correct? I thing, so there are not problem ensure an
using VARIADIC keyword in this context - but, personally I don't feel,
so there it have to be. But I don't thing, so this is important
(minimally for me) - I'll accept others opinions.

Regards
Pavel

Show quoted text

I'm still reviewing the code.

Jeff,

When will you be able to post this review?

Thanks,

...Robert

#21Robert Haas
robertmhaas@gmail.com
In reply to: Pavel Stehule (#20)
Re: Issues for named/mixed function notation patch

On Sun, Sep 27, 2009 at 1:46 PM, Pavel Stehule <pavel.stehule@gmail.com> wrote:

2009/9/27 Robert Haas <robertmhaas@gmail.com>:

On Sun, Sep 27, 2009 at 12:37 AM, Pavel Stehule <pavel.stehule@gmail.com> wrote:

"However, a named variadic argument can only be called the way shown in
the example above. The VARIADIC keyword must not be specified and a
variadic notation of all arguments is not supported. To use variadic
argument lists you must use positional notation instead."

What is the intended behavior? I think we should always require VARIADIC
to be specified regardless of using named notation.

maybe we could to support variadic named parameters in future - then
using VARIADIC keyword should be necessary - like

foo(10 AS p1, 20 AS p1, 30 AS p3) is equalent of
foo(VARIADIC ARRAY[10,20] AS p1, 30 AS p3)

Pavel,

This doesn't make sense to me, FWIW.  I don't think we should allow
parameters to be specified more than once.  It's hard for me to
imagine how that could be useful.

ook I thing, so this should be little bit unclean too. I though why we
need VARIADIC keyword mandatory for named notation. When we could
specify only unique names, then we could use only one "packed"
variadic parameter - and then VARIADIC keyword isn't necessary.

Is this idea correct? I thing, so there are not problem ensure an
using VARIADIC keyword in this context - but, personally I don't feel,
so there it have to be. But I don't thing, so this is important
(minimally for me) - I'll accept others opinions.

Sorry, I'm having trouble understanding what you're driving at here.
I think we should just not allow named notation to be combined with
VARIADIC, at least for a first version of this feature, either when
defining a function or when calling one. We can consider relaxing
that restriction at a later date if we can agree on what the semantics
should be.

...Robert

#22Pavel Stehule
pavel.stehule@gmail.com
In reply to: Robert Haas (#21)
Re: Issues for named/mixed function notation patch

Sorry, I'm having trouble understanding what you're driving at here.
I think we should just not allow named notation to be combined with
VARIADIC, at least for a first version of this feature, either when
defining a function or when calling one.  We can consider relaxing
that restriction at a later date if we can agree on what the semantics
should be.

This is maybe too strict. I thing, so safe version is allow variadic
packed parameter with VARIADIC keyword as Jeff proposes.

I'll send actualised patch today.

Pavel

Show quoted text

...Robert

#23Jeff Davis
pgsql@j-davis.com
In reply to: Pavel Stehule (#22)
Re: Issues for named/mixed function notation patch

On Mon, 2009-09-28 at 11:50 +0200, Pavel Stehule wrote:

This is maybe too strict. I thing, so safe version is allow variadic
packed parameter with VARIADIC keyword as Jeff proposes.

The combination of variadic parameters and named call notation is
somewhat strange, on second thought. Can you identify a use case?

If not, then it should probably be blocked in this version of the patch.
Even if it makes sense from a syntax standpoint, it might be confusing
to users.

Robert, did you have a specific concern in mind? Do you see a behavior
there that we might want to change in the future?

Regards,
Jeff Davis

#24Pavel Stehule
pavel.stehule@gmail.com
In reply to: Jeff Davis (#23)
Re: Issues for named/mixed function notation patch

2009/9/28 Jeff Davis <pgsql@j-davis.com>:

On Mon, 2009-09-28 at 11:50 +0200, Pavel Stehule wrote:

This is maybe too strict. I thing, so safe version is allow variadic
packed parameter with VARIADIC keyword as Jeff proposes.

The combination of variadic parameters and named call notation is
somewhat strange, on second thought. Can you identify a use case?

I have not any use case now. Simply when I have a variadic function,
then I would to allow call it with named notation. Some like

create or replace foo (a int, variadic b int[]) ...

SELECT foo(10 as int, variadic array[10,20] as b)

If not, then it should probably be blocked in this version of the patch.
Even if it makes sense from a syntax standpoint, it might be confusing
to users.

when I though about control, I found so syntax with mandatory VARIADIC
is difficult implementable. So probably the most feasible solution for
this moment is to discard a variadic functions from set of functions
that are callable with named notation. So I thing we are in tune, and
I am going to update patch.

Regards
Pavel Stehule

Show quoted text

Robert, did you have a specific concern in mind? Do you see a behavior
there that we might want to change in the future?

Regards,
       Jeff Davis

#25Jeff Davis
pgsql@j-davis.com
In reply to: Pavel Stehule (#24)
Re: Issues for named/mixed function notation patch

On Mon, 2009-09-28 at 18:23 +0200, Pavel Stehule wrote:

when I though about control, I found so syntax with mandatory VARIADIC
is difficult implementable. So probably the most feasible solution for
this moment is to discard a variadic functions from set of functions
that are callable with named notation. So I thing we are in tune, and
I am going to update patch.

Sounds good. I am looking at the code, and there's a part I don't
understand:

In FuncnameGetCandidates():
/*
* Wait with apply proargidxs on args. Detection ambigouos needs
* consistent args (based on proargs). Store proargidxs for later
* use.
*/
newResult->proargidxs = proargidxs;

But after calling FuncnameGetCandidates (the only place where fargnames
is non-NIL), you immediately re-assign to best_candidate->args. What
happens between those two places, and why can't it happen in
FuncnameGetCandidates?

Also, you should consistently pass NIL when you mean an empty list, but
sometimes you pass NULL to FuncnameGetCandidates().

Regards,
Jeff Davis

#26Pavel Stehule
pavel.stehule@gmail.com
In reply to: Jeff Davis (#25)
Re: Issues for named/mixed function notation patch

2009/9/28 Jeff Davis <pgsql@j-davis.com>:

On Mon, 2009-09-28 at 18:23 +0200, Pavel Stehule wrote:

when I though about control, I found so syntax with mandatory VARIADIC
is difficult implementable. So probably the most feasible solution for
this moment is to discard a variadic functions from set of functions
that are callable with named notation. So I thing we are in tune, and
I am going to update patch.

Sounds good. I am looking at the code, and there's a part I don't
understand:

In FuncnameGetCandidates():
 /*
  * Wait with apply proargidxs on args. Detection ambigouos needs
  * consistent args (based on proargs). Store proargidxs for later
  * use.
  */
  newResult->proargidxs = proargidxs;

But after calling FuncnameGetCandidates (the only place where fargnames
is non-NIL), you immediately re-assign to best_candidate->args. What
happens between those two places, and why can't it happen in
FuncnameGetCandidates?

I am not sure - I have to look to code, but if I remember well, there
are same arrays, with same values, but the field are different order.
One is related to pgproc and second to real params. But I have to
check code again.

Also, you should consistently pass NIL when you mean an empty list, but
sometimes you pass NULL to FuncnameGetCandidates().

It's bug, where is it?

Regards
Pavel

Show quoted text

Regards,
       Jeff Davis

#27Jeff Davis
pgsql@j-davis.com
In reply to: Pavel Stehule (#26)
Re: Issues for named/mixed function notation patch

On Mon, 2009-09-28 at 19:26 +0200, Pavel Stehule wrote:

Also, you should consistently pass NIL when you mean an empty list, but
sometimes you pass NULL to FuncnameGetCandidates().

It's bug, where is it?

In regproc.c.

Jeff

#28Pavel Stehule
pavel.stehule@gmail.com
In reply to: Pavel Stehule (#26)
1 attachment(s)
Re: Issues for named/mixed function notation patch

2009/9/28 Pavel Stehule <pavel.stehule@gmail.com>:

2009/9/28 Jeff Davis <pgsql@j-davis.com>:

On Mon, 2009-09-28 at 18:23 +0200, Pavel Stehule wrote:

when I though about control, I found so syntax with mandatory VARIADIC
is difficult implementable. So probably the most feasible solution for
this moment is to discard a variadic functions from set of functions
that are callable with named notation. So I thing we are in tune, and
I am going to update patch.

Sounds good. I am looking at the code, and there's a part I don't
understand:

In FuncnameGetCandidates():
 /*
  * Wait with apply proargidxs on args. Detection ambigouos needs
  * consistent args (based on proargs). Store proargidxs for later
  * use.
  */
  newResult->proargidxs = proargidxs;

proargidxs is used more times in func_get_detail function

a) for reordering pgproc->args to actual params order
b) for numbering (filling) NamedArgExpr->position based on known best candidate

But after calling FuncnameGetCandidates (the only place where fargnames
is non-NIL), you immediately re-assign to best_candidate->args. What
happens between those two places, and why can't it happen in
FuncnameGetCandidates?

I am not sure - I have to look to code, but if I remember well, there
are same arrays, with same values, but the field are different order.
One is related to pgproc and second to real params. But I have to
check code again.

Also, you should consistently pass NIL when you mean an empty list, but
sometimes you pass NULL to FuncnameGetCandidates().

It's bug, where is it?

I fixed it

So I dropped variadic functions from mixed/named notation and little
bit modified documentation. Please, can some native English speaker
look on documentation?

Patch attached

Pavel

Show quoted text

Regards
Pavel

Regards,
       Jeff Davis

Attachments:

plpgsql-move-fix090928a.difftext/x-patch; charset=US-ASCII; name=plpgsql-move-fix090928a.diffDownload
*** ./doc/src/sgml/xfunc.sgml.orig	2009-09-14 11:54:56.981283116 +0200
--- ./doc/src/sgml/xfunc.sgml	2009-09-29 18:08:22.809009405 +0200
***************
*** 1101,1106 ****
--- 1101,1262 ----
     </para>
    </sect1>
  
+   <sect1 id="xfunc-notation">
+    <title>Positional and named notation</title>
+ 
+    <indexterm zone="xfunc-notation">
+     <primary>notation</primary>
+     <secondary>functions</secondary>
+    </indexterm>
+ 
+    <para>
+     Functions with named parameters can be called by <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. This is also closer to
+     some other SQL dialects which should make porting applications easier. The <firstterm>positional</firstterm>
+     notation calls the function with its argument values in the same order as defined in the function declaration.
+     Using <firstterm>named</firstterm> notation allows to
+     pass arguments by its name to a function, the positional order doesn't need to be preserved. Both 
+     <firstterm>named</firstterm> and <firstterm>positional</firstterm> notation can be mixed 
+     (<firstterm>mixed</firstterm> notation). However, <firstterm>positional</firstterm> notation is 
+     only allowed from the left to the right in the argument list.
+     As soon as a <firstterm>named</firstterm> argument appears in the list, <firstterm>named</firstterm> 
+     notation have to be used for all following arguments. Arguments with default values can be omitted and
+     don't have to be specified. The default values of such arguments will then be used instead. The following
+     example 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 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>
+ <literal>Positional</literal> notation is the traditional behavior how arguments are passed 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 get its
+ default value <literal>false</literal> assigned implicitely. 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 the argument <literal>uppercase</literal> 
+ will have <literal>true</literal> assigned explicitely and concat <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. Furthermore, 
+ when using <literal>named</literal> notation the order of the arguments doesn't matter, 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>
+ In the examples above, the <firstterm>named</firstterm> notation allows to specify the argument values out of
+ their original order as they would occur in <firstterm>positional</firstterm> notation. It isn't possible to use
+ <firstterm>named</firstterm> or <firstterm>mixed</firstterm> notation for variadic function. Variadic functions are based
+ on positions of every parameter and positions has no sense in these notations.
+     </para>
+   </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, positional argument have to occur from left to right, named
+ arguments cannot precede positional arguments. This means that in <firstterm>mixed</firstterm> notation named
+ arguments cannot be defined before 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 first query above is correct, since the argument <literal>a</literal> is defined in
+ <firstterm>positional</firstterm> notation before any named arguments. However, the following example
+ isn't allowed to work, since <literal>a</literal> precedes 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-09-14 11:54:56.986283503 +0200
--- ./src/backend/catalog/namespace.c	2009-09-29 18:46:58.275008976 +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,724 ----
  		int			effective_nargs;
  		int			pathpos = 0;
  		bool		variadic;
! 		bool		use_defaults = false;		/* be 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 
! 			 *
! 			 * We would to disable an call of variadic function with named
! 			 * or mixed notation, because it could be messy for users. We
! 			 * would to allow only unique arg names, and this is useles for
! 			 * variadic functions.
! 			 */
! 			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 ****
--- 758,770 ----
  		newResult->pathpos = pathpos;
  		newResult->oid = HeapTupleGetOid(proctup);
  		newResult->nargs = effective_nargs;
+ 
+ 		/*
+ 		 * Wait with apply proargidxs on args. Detection ambigouos needs
+ 		 * consistent args (based on proargs). Store proargidxs for later
+ 		 * use.
+ 		 */
+ 		newResult->proargidxs = proargidxs; 
  		memcpy(newResult->args, procform->proargtypes.values,
  			   pronargs * sizeof(Oid));
  		if (variadic)
***************
*** 886,891 ****
--- 929,1060 ----
  }
  
  /*
+  * 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);
+ 
+ 	/* 
+ 	 * A number less or equal nargs means explicit arguments,
+ 	*/
+ 	*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++;
+ 	}
+ 
+ 	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)
  		{
--- 1101,1107 ----
  		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-09-14 11:54:56.991282493 +0200
--- ./src/backend/catalog/pg_aggregate.c	2009-09-15 08:43:03.755405767 +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-09-14 11:54:56.996283718 +0200
--- ./src/backend/catalog/pg_proc.c	2009-09-15 08:43:03.764394113 +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,524 ----
  				newlc = lnext(newlc);
  			}
  		}
+ 		
+ 		/*
+ 		 * if there are named parameters, check names equality. 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-14 11:54:57.015284574 +0200
--- ./src/backend/nodes/copyfuncs.c	2009-09-15 08:43:03.789394086 +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 *
***************
*** 3564,3569 ****
--- 3581,3589 ----
  		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-14 11:54:57.040290975 +0200
--- ./src/backend/nodes/equalfuncs.c	2009-09-15 08:43:03.806392155 +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);
***************
*** 2356,2361 ****
--- 2368,2376 ----
  		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-09-14 11:54:57.048283381 +0200
--- ./src/backend/nodes/makefuncs.c	2009-09-15 08:43:03.842399174 +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-09-14 11:54:57.071329465 +0200
--- ./src/backend/nodes/nodeFuncs.c	2009-09-15 08:43:03.858390685 +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-14 11:54:57.093284622 +0200
--- ./src/backend/nodes/outfuncs.c	2009-09-15 08:43:03.880394169 +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");
***************
*** 2504,2509 ****
--- 2516,2524 ----
  			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-09-14 11:54:57.117797663 +0200
--- ./src/backend/nodes/readfuncs.c	2009-09-15 08:43:03.916390856 +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-09-14 11:54:57.122283736 +0200
--- ./src/backend/optimizer/util/clauses.c	2009-09-15 08:43:03.941393341 +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 change order of any arg in arglist. When some arguments missing,
!  * then it use 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-08-19 01:40:20.000000000 +0200
--- ./src/backend/parser/gram.y	2009-09-15 08:43:03.994390890 +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
***************
*** 349,354 ****
--- 352,359 ----
  %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
***************
*** 4694,4700 ****
  
  func_args_list:
  			func_arg								{ $$ = list_make1($1); }
! 			| func_args_list ',' func_arg			{ $$ = lappend($1, $3); }
  		;
  
  /*
--- 4699,4705 ----
  
  func_args_list:
  			func_arg								{ $$ = list_make1($1); }
! 			| func_args_list ',' func_arg						{ $$ = AppendFuncParameter($1, $3, @3, yyscanner); }
  		;
  
  /*
***************
*** 4708,4715 ****
  
  func_args_with_defaults_list:
  		func_arg_with_default						{ $$ = list_make1($1); }
! 		| func_args_with_defaults_list ',' func_arg_with_default
! 													{ $$ = lappend($1, $3); }
  		;
  
  /*
--- 4713,4719 ----
  
  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); }
  		;
  
  /*
***************
*** 8858,8864 ****
  					n->location = @1;
  					$$ = (Node *)n;
  				}
! 			| func_name '(' expr_list ')' over_clause
  				{
  					FuncCall *n = makeNode(FuncCall);
  					n->funcname = $1;
--- 8862,8868 ----
  					n->location = @1;
  					$$ = (Node *)n;
  				}
! 			| func_name '(' func_arg_list ')' over_clause
  				{
  					FuncCall *n = makeNode(FuncCall);
  					n->funcname = $1;
***************
*** 8870,8876 ****
  					n->location = @1;
  					$$ = (Node *)n;
  				}
! 			| func_name '(' VARIADIC a_expr ')' over_clause
  				{
  					FuncCall *n = makeNode(FuncCall);
  					n->funcname = $1;
--- 8874,8880 ----
  					n->location = @1;
  					$$ = (Node *)n;
  				}
! 			| func_name '(' VARIADIC func_arg_expr ')' over_clause
  				{
  					FuncCall *n = makeNode(FuncCall);
  					n->funcname = $1;
***************
*** 8882,8888 ****
  					n->location = @1;
  					$$ = (Node *)n;
  				}
! 			| func_name '(' expr_list ',' VARIADIC a_expr ')' over_clause
  				{
  					FuncCall *n = makeNode(FuncCall);
  					n->funcname = $1;
--- 8886,8892 ----
  					n->location = @1;
  					$$ = (Node *)n;
  				}
! 			| func_name '(' func_arg_list ',' VARIADIC func_arg_expr ')' over_clause
  				{
  					FuncCall *n = makeNode(FuncCall);
  					n->funcname = $1;
***************
*** 8894,8900 ****
  					n->location = @1;
  					$$ = (Node *)n;
  				}
! 			| func_name '(' ALL expr_list ')' over_clause
  				{
  					FuncCall *n = makeNode(FuncCall);
  					n->funcname = $1;
--- 8898,8904 ----
  					n->location = @1;
  					$$ = (Node *)n;
  				}
! 			| func_name '(' ALL func_arg_list ')' over_clause
  				{
  					FuncCall *n = makeNode(FuncCall);
  					n->funcname = $1;
***************
*** 8910,8916 ****
  					n->location = @1;
  					$$ = (Node *)n;
  				}
! 			| func_name '(' DISTINCT expr_list ')' over_clause
  				{
  					FuncCall *n = makeNode(FuncCall);
  					n->funcname = $1;
--- 8914,8920 ----
  					n->location = @1;
  					$$ = (Node *)n;
  				}
! 			| func_name '(' DISTINCT func_arg_list ')' over_clause
  				{
  					FuncCall *n = makeNode(FuncCall);
  					n->funcname = $1;
***************
*** 9633,9638 ****
--- 9637,9669 ----
  				}
  		;
  
+ /* 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); }
  		;
***************
*** 10099,10108 ****
  					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);
--- 10130,10151 ----
  					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);
***************
*** 11202,11207 ****
--- 11245,11290 ----
  }
  
  /*
+  * Append function parameter to function's parameter list. Reject 
+  * parameters with uniqueless 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 not 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-09-14 11:54:57.133283526 +0200
--- ./src/backend/parser/parse_expr.c	2009-09-15 08:43:04.029391914 +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-09-14 11:54:57.139283488 +0200
--- ./src/backend/parser/parse_func.c	2009-09-29 19:01:18.666027490 +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 not unique name"),
+ 								 errhint("Verify 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);
+ 		}
+ 	} 
+ 	
+ 	/* forgot 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,1166 ----
  				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);
! 					}
! 					
! 					/* 
! 					 * Actually only first nargs field of best_candidate->args is valid,
! 					 * Now, we have to refresh last ndargs items.
! 					 */
! 					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++;
! 	}
  }
  
  /*
--- 1206,1251 ----
  		/* 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)
  	{
--- 1452,1458 ----
  {
  	FuncCandidateList clist;
  
! 	clist = FuncnameGetCandidates(funcname, nargs, NIL, false, false);
  
  	while (clist)
  	{
*** ./src/backend/utils/adt/regproc.c.orig	2009-09-15 08:25:33.953393141 +0200
--- ./src/backend/utils/adt/regproc.c	2009-09-29 17:48:44.300010575 +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-09-14 11:54:57.160434628 +0200
--- ./src/backend/utils/adt/ruleutils.c	2009-09-15 08:43:04.082390582 +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-09-14 11:54:57.165283040 +0200
--- ./src/include/catalog/namespace.h	2009-09-15 08:43:04.095391193 +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-09-14 11:54:57.169283294 +0200
--- ./src/include/nodes/nodes.h	2009-09-15 08:43:04.107390833 +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-09-14 11:54:57.178283934 +0200
--- ./src/include/nodes/parsenodes.h	2009-09-15 08:43:04.126390567 +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-09-14 11:54:57.180280010 +0200
--- ./src/include/nodes/primnodes.h	2009-09-15 08:43:04.144390726 +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,346 ----
  	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
+  *
+  * It is used, when argument has name. When positional notation is used, then
+  * args list doesn't contain any NamedArgExpr. Named notation means, so all
+  * arguments in list are NamedArgExpr. Mixed notation means, so 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-09-14 11:54:57.181280982 +0200
--- ./src/include/parser/parse_func.h	2009-09-15 08:43:04.152391510 +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-09-14 11:54:57.183280131 +0200
--- ./src/test/regress/expected/create_view.out	2009-09-15 08:43:04.197391629 +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-09-14 11:54:57.184279705 +0200
--- ./src/test/regress/expected/polymorphism.out	2009-09-29 17:55:19.000000000 +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-09-14 11:54:57.186279413 +0200
--- ./src/test/regress/expected/rangefuncs.out	2009-09-15 08:43:04.226394647 +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 not 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 not 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 not 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 not 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-09-14 11:54:57.188279679 +0200
--- ./src/test/regress/sql/create_view.sql	2009-09-15 08:43:04.256395000 +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-09-14 11:54:57.190281343 +0200
--- ./src/test/regress/sql/polymorphism.sql	2009-09-29 17:52:59.170011067 +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-09-14 11:54:57.191280080 +0200
--- ./src/test/regress/sql/rangefuncs.sql	2009-09-15 08:43:04.282395665 +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);
+ 
#29Brendan Jurd
direvus@gmail.com
In reply to: Pavel Stehule (#28)
1 attachment(s)
Re: Issues for named/mixed function notation patch

2009/9/30 Pavel Stehule <pavel.stehule@gmail.com>:

So I dropped variadic functions from mixed/named notation and little
bit modified documentation. Please, can some native English speaker
look on documentation?

Hi Pavel,

I've had a look through the documentation and cleaned up a few things.
I changed the chapter heading from "Positional and named notation" to
"Calling Functions". I felt that the original heading would not give
a clear hint about the subject matter to anyone who wasn't already
familiar with the terminology.

The rest of my changes are rephrasing sentences, fixing spelling and
grammar, and cleaning up indentation and wrapping. The code examples
are not changed and I haven't meddled with the structure of the
chapter.

I hope you find this helpful.

Cheers,
BJ

Attachments:

named-notation-doc-fixes.diffapplication/octet-stream; name=named-notation-doc-fixes.diffDownload
diff --git a/doc/src/sgml/xfunc.sgml b/doc/src/sgml/xfunc.sgml
index 016ad36..df73bfd 100644
--- a/doc/src/sgml/xfunc.sgml
+++ b/doc/src/sgml/xfunc.sgml
@@ -1102,7 +1102,7 @@ CREATE FUNCTION test(int, int) RETURNS int
   </sect1>
 
   <sect1 id="xfunc-notation">
-   <title>Positional and named notation</title>
+   <title>Calling Functions</title>
 
    <indexterm zone="xfunc-notation">
     <primary>notation</primary>
@@ -1110,23 +1110,24 @@ CREATE FUNCTION test(int, int) RETURNS int
    </indexterm>
 
    <para>
-    Functions with named parameters can be called by <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. This is also closer to
-    some other SQL dialects which should make porting applications easier. The <firstterm>positional</firstterm>
-    notation calls the function with its argument values in the same order as defined in the function declaration.
-    Using <firstterm>named</firstterm> notation allows to
-    pass arguments by its name to a function, the positional order doesn't need to be preserved. Both 
-    <firstterm>named</firstterm> and <firstterm>positional</firstterm> notation can be mixed 
-    (<firstterm>mixed</firstterm> notation). However, <firstterm>positional</firstterm> notation is 
-    only allowed from the left to the right in the argument list.
-    As soon as a <firstterm>named</firstterm> argument appears in the list, <firstterm>named</firstterm> 
-    notation have to be used for all following arguments. Arguments with default values can be omitted and
-    don't have to be specified. The default values of such arguments will then be used instead. The following
-    example will illustrate the usage of all three kinds of notation.
-    
-
+    <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
@@ -1139,12 +1140,14 @@ $$
 $$ 
 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 calling
-     function with default values.
+    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">
@@ -1155,9 +1158,10 @@ LANGUAGE SQL IMMUTABLE STRICT;
     <secondary>positional notation</secondary>
    </indexterm>
 
-    <para>
-<literal>Positional</literal> notation is the traditional behavior how arguments are passed to functions in 
-<productname>PostgreSQL</productname>, for example:
+   <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
@@ -1165,10 +1169,11 @@ SELECT concat_lower_or_upper('Hello', 'World');
  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 get its
-default value <literal>false</literal> assigned implicitely. Another example:
+    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
@@ -1176,35 +1181,39 @@ SELECT concat_lower_or_upper('Hello', 'World', true);
  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 the argument <literal>uppercase</literal> 
-will have <literal>true</literal> assigned explicitely and concat <literal>a</literal> and <literal>b</literal>
-in uppercase.
-    </para>
+    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>
+   <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.
+   <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);
+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. Furthermore, 
-when using <literal>named</literal> notation the order of the arguments doesn't matter, for example:
+    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);
+SELECT concat_lower_or_upper('Hello' AS a, 'World' AS b, true AS uppercase);
  concat_lower_or_upper
 -----------------------
  HELLO WORLD
@@ -1216,26 +1225,28 @@ SELECT concat_lower_or_upper('Hello' AS a, true AS uppercase, 'World' AS b);
  HELLO WORLD
 (1 row)
 </screen>
-In the examples above, the <firstterm>named</firstterm> notation allows to specify the argument values out of
-their original order as they would occur in <firstterm>positional</firstterm> notation. It isn't possible to use
-<firstterm>named</firstterm> or <firstterm>mixed</firstterm> notation for variadic function. Variadic functions are based
-on positions of every parameter and positions has no sense in these notations.
+   </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>
+   <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, positional argument have to occur from left to right, named
-arguments cannot precede positional arguments. This means that in <firstterm>mixed</firstterm> notation named
-arguments cannot be defined before positional arguments.
+   <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
@@ -1243,9 +1254,11 @@ SELECT concat_lower_or_upper('Hello', 'World' AS b, true AS uppercase);
  HELLO WORLD
 (1 row)
 </screen>
-The first query above is correct, since the argument <literal>a</literal> is defined in
-<firstterm>positional</firstterm> notation before any named arguments. However, the following example
-isn't allowed to work, since <literal>a</literal> precedes the named argument <literal>b</literal>.
+    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
#30Pavel Stehule
pavel.stehule@gmail.com
In reply to: Brendan Jurd (#29)
Re: Issues for named/mixed function notation patch

2009/10/1 Brendan Jurd <direvus@gmail.com>:

2009/9/30 Pavel Stehule <pavel.stehule@gmail.com>:

So I dropped variadic functions from mixed/named notation and little
bit modified documentation. Please, can some native English speaker
look on documentation?

Hi Pavel,

I've had a look through the documentation and cleaned up a few things.
 I changed the chapter heading from "Positional and named notation" to
"Calling Functions".  I felt that the original heading would not give
a clear hint about the subject matter to anyone who wasn't already
familiar with the terminology.

The rest of my changes are rephrasing sentences, fixing spelling and
grammar, and cleaning up indentation and wrapping.  The code examples
are not changed and I haven't meddled with the structure of the
chapter.

I hope you find this helpful.

yes, it's very helpful. I thing, so there is all what is important.

thank you
Pavel

Show quoted text

Cheers,
BJ

#31Jeff Davis
pgsql@j-davis.com
In reply to: Brendan Jurd (#29)
1 attachment(s)
Re: Issues for named/mixed function notation patch

On Thu, 2009-10-01 at 17:56 +1000, Brendan Jurd wrote:

I've had a look through the documentation and cleaned up a few things.

Thanks, that is helpful. I have included that along with some other
comment updates in the attached patch.

Paval,

In ProcedureCreate(), you match the argument names to see if anything
changed (in which case you raise an error). The code for that looks more
complex than I expected because it keeps track of the two argument lists
using different array indexes (i and j). Is there a reason it you can't
just iterate through with something like:

if (p_oldargmodes[i] == PROARGMODE_OUT ||
p_oldargmodes[i] == PROARGMODE_TABLE)
continue;

if (strcmp(p_oldargnames[i], p_names[i]) != 0)
elog(ERROR, ...

I'm oversimplifying, of course, but I don't understand why you need both
i and j. Also, there is some unnecessarily verbose code like:

if (p_modes == NULL || (p_modes != NULL ...

In func_get_detail(), there is:

/* shouldn't happen, FuncnameGetCandidates messed up */
if (best_candidate->ndargs > pform->pronargdefaults)
elog(ERROR, "not enough default arguments");

Why is it only an error if ndargs is greater? Shouldn't they be equal?

/*
* Actually only first nargs field of best_candidate->args is valid,
* Now, we have to refresh last ndargs items.
*/

Can you explain the above comment?

Please review Brendan and my patches and combine them with your patch.

Regards,
Jeff Davis

Attachments:

named-mixed.patchtext/x-patch; charset=UTF-8; name=named-mixed.patchDownload
diff --git a/doc/src/sgml/syntax.sgml b/doc/src/sgml/syntax.sgml
index 50c4128..542646d 100644
--- a/doc/src/sgml/syntax.sgml
+++ b/doc/src/sgml/syntax.sgml
@@ -1505,6 +1505,10 @@ sqrt(2)
     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">
diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c
index 9e8ccfa..1c06885 100644
--- a/src/backend/catalog/namespace.c
+++ b/src/backend/catalog/namespace.c
@@ -651,21 +651,19 @@ FuncnameGetCandidates(List *names, int nargs, List *argnames,
 		int			effective_nargs;
 		int			pathpos = 0;
 		bool		variadic;
-		bool		use_defaults = false;		/* be compiler quiet */
+		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. */
+		/* Try to attach names when mixed or named notation is used. */
 		if (argnames != NIL)
 		{
 			/*
-			 * Mixed or named notation 
+			 * Mixed or named notation
 			 *
-			 * We would to disable an call of variadic function with named
-			 * or mixed notation, because it could be messy for users. We
-			 * would to allow only unique arg names, and this is useles for
-			 * variadic functions.
+			 * Variadic functions can't be called using named or mixed
+			 * notation.
 			 */
 			if (OidIsValid(procform->provariadic))
 				continue;
@@ -760,9 +758,12 @@ FuncnameGetCandidates(List *names, int nargs, List *argnames,
 		newResult->nargs = effective_nargs;
 
 		/*
-		 * Wait with apply proargidxs on args. Detection ambigouos needs
-		 * consistent args (based on proargs). Store proargidxs for later
-		 * use.
+		 * 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,
@@ -980,8 +981,9 @@ VerifyCandidateNamedNotation(HeapTuple proctup, int pronargs, int nargs, List *a
 	Assert(p_argnames != NULL);
 
 	/* 
-	 * A number less or equal nargs means explicit arguments,
-	*/
+	 * pronargs equal to nargs means explicit arguments (no defaults)
+	 */
+
 	*proargidxs = palloc(nargs * sizeof(int));
 	for (i = 0; i < pronargs; i++)
 		argfilling[i] = false;
@@ -1004,7 +1006,7 @@ VerifyCandidateNamedNotation(HeapTuple proctup, int pronargs, int nargs, List *a
 					continue;
 				if (p_argnames[i] && strcmp(p_argnames[i], argname) == 0)
 				{
-					/*  protect us against duplicated entries from bad written  mixed notation */
+					/*  protect us against duplicated entries from badly written  mixed notation */
 					if (argfilling[pp])
 						return false;
 
@@ -1035,9 +1037,13 @@ VerifyCandidateNamedNotation(HeapTuple proctup, int pronargs, int nargs, List *a
 		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 ? */
+	/* Check for default arguments */
 	if (nargs < pronargs)
 	{
 		int first_arg_with_default = pronargs - pronargdefaults;
diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c
index c501a5e..0a34e81 100644
--- a/src/backend/catalog/pg_proc.c
+++ b/src/backend/catalog/pg_proc.c
@@ -445,9 +445,10 @@ ProcedureCreate(const char *procedureName,
 		}
 		
 		/*
-		 * if there are named parameters, check names equality. Any change can break
-		 * exiting calls (when named parameters are used). Only IN and INOUT parameters are 
-		 * checked.
+		 * 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,
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index ccc6951..3f67607 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -3300,8 +3300,8 @@ simplify_function(Oid funcid, Oid result_type, int32 result_typmod,
 }
 
 /*
- * This function change order of any arg in arglist. When some arguments missing,
- * then it use defaults.
+ * 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,
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index a3d2d94..e86ce8a 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -11332,7 +11332,7 @@ TableFuncTypeName(List *columns)
 
 /*
  * Append function parameter to function's parameter list. Reject 
- * parameters with uniqueless param_name with same proargmode.
+ * parameters with non-unique param_name with same proargmode.
  * It's enough for sql, plperl, plpython language, but not for
  * plpgsql. 
  * 
@@ -11363,7 +11363,7 @@ AppendFuncParameter(List *list, FunctionParameter *p, int location, base_yyscan_
 			if (p2->name != NULL && strcmp(p->name, p2->name) == 0)
 				ereport(ERROR, 
 						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("parameter has not unique name"),
+						 errmsg("parameter has non-unique name"),
 						  parser_errposition(location)));
 		}
 	
diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c
index e1c8a1c..5ea00c6 100644
--- a/src/backend/parser/parse_func.c
+++ b/src/backend/parser/parse_func.c
@@ -159,8 +159,8 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
 					if (strcmp(n->name, next_name) == 0)
 						ereport(ERROR,
 								(errcode(ERRCODE_SYNTAX_ERROR),
-								 errmsg("named argument has not unique name"),
-								 errhint("Verify your named parameters for ambiguous argument names."),
+								 errmsg("named argument has non-unique name"),
+								 errhint("Check your named parameters for ambiguous argument names."),
 								 parser_errposition(pstate, exprLocation((Node *) lfirst(lc)))));
 				}
 			}
@@ -179,7 +179,7 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
 		}
 	} 
 	
-	/* forgot argnames list of empty strings when positional notation */
+	/* forget argnames list of empty strings when positional notation */
 	if (notation == CALL_NOTATION_POSITIONAL)
 		fargnames = NIL; 
 
diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h
index dab89ba..32620fe 100644
--- a/src/include/nodes/primnodes.h
+++ b/src/include/nodes/primnodes.h
@@ -326,10 +326,11 @@ typedef struct FuncExpr
 /*
  * NamedArgExpr - an named argument of function
  *
- * It is used, when argument has name. When positional notation is used, then
- * args list doesn't contain any NamedArgExpr. Named notation means, so all
- * arguments in list are NamedArgExpr. Mixed notation means, so first n arguments
- * are Exprs and last m arguments are NamedArgExpr.
+ * 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
 {
diff --git a/src/test/regress/expected/rangefuncs.out b/src/test/regress/expected/rangefuncs.out
index cd437ca..dfac452 100644
--- a/src/test/regress/expected/rangefuncs.out
+++ b/src/test/regress/expected/rangefuncs.out
@@ -838,19 +838,19 @@ 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 not unique name
+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 not unique name
+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 not unique name
+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 not unique name
+ERROR:  parameter has non-unique name
 LINE 1: create function testfoo(a int, inout a int) returns int as $...
                                        ^
 -- valid
#32Pavel Stehule
pavel.stehule@gmail.com
In reply to: Jeff Davis (#31)
Re: Issues for named/mixed function notation patch

2009/10/2 Jeff Davis <pgsql@j-davis.com>:

On Thu, 2009-10-01 at 17:56 +1000, Brendan Jurd wrote:

I've had a look through the documentation and cleaned up a few things.

Thanks, that is helpful. I have included that along with some other
comment updates in the attached patch.

Paval,

In ProcedureCreate(), you match the argument names to see if anything
changed (in which case you raise an error). The code for that looks more
complex than I expected because it keeps track of the two argument lists
using different array indexes (i and j). Is there a reason it you can't
just iterate through with something like:

 if (p_oldargmodes[i] == PROARGMODE_OUT ||
     p_oldargmodes[i] == PROARGMODE_TABLE)
   continue;

 if (strcmp(p_oldargnames[i], p_names[i]) != 0)
   elog(ERROR, ...

I testing visible interface from outside.

from outside the following functions are same:

foo1(in a1, in a2, in a3, out a1, out a2, out a3)
foo2(in a1, out a1, in a2, out a2, in a3, out a3)

so the used test is immune to this change.

I'm oversimplifying, of course, but I don't understand why you need both
i and j. Also, there is some unnecessarily verbose code like:

 if (p_modes == NULL || (p_modes != NULL ...

when p_modes is null,then all arguments are input. So input parameter
is when p_modes is null (all parameters are input) or is "in",
"inout", "variadic".

In func_get_detail(), there is:

 /* shouldn't happen, FuncnameGetCandidates messed up */
 if (best_candidate->ndargs > pform->pronargdefaults)
   elog(ERROR, "not enough default arguments");

best_candidate->ndargs ~ use n default values, it have to be less or
equal than declared defaults in pgproc.

Why is it only an error if ndargs is greater? Shouldn't they be equal?

ndargs == pronargdefaults is correct - it means, use all declared
defaults. But, raise exception when you would to use more defaults
than is declared.

 /*
  * Actually only first nargs field of best_candidate->args is valid,
  * Now, we have to refresh last ndargs items.
  */

Can you explain the above comment?

this is not good formulation. It means, so in this moment we processed
nargs fields, and we have to process others ndargs fields. But i named
or mixed notation, the processed fields should not be first nargs
fields (like positional notation). There should be a gap, that are
filled by defaults. Gaps are identified via bitmap created on cycle
above. In this cycle is processed positional parameters (with
increasing i) and named parameters. Because positional parameters have
to be front of named parameters, then we don't need increase i when
process named p.,

Please review Brendan and my patches and combine them with your patch.

yes, I'll go on this evening, thank you.

Pavel

Show quoted text

Regards,
       Jeff Davis

#33Pavel Stehule
pavel.stehule@gmail.com
In reply to: Jeff Davis (#31)
1 attachment(s)
Re: Issues for named/mixed function notation patch

Please review Brendan and my patches and combine them with your patch.

see attachment, please

regards
pavel

Show quoted text

Regards,
       Jeff Davis

Attachments:

mixednamedp091001.diffapplication/octet-stream; name=mixednamedp091001.diffDownload
*** ./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);
+ 
#34Jeff Davis
pgsql@j-davis.com
In reply to: Pavel Stehule (#33)
Re: Issues for named/mixed function notation patch

On Fri, 2009-10-02 at 16:06 +0200, Pavel Stehule wrote:

see attachment, please

Thank you, marked as "ready for committer".

Regards,
Jeff Davis

#35Tom Lane
tgl@sss.pgh.pa.us
In reply to: Pavel Stehule (#22)
Re: Issues for named/mixed function notation patch

Pavel Stehule <pavel.stehule@gmail.com> writes:

Sorry, I'm having trouble understanding what you're driving at here.
I think we should just not allow named notation to be combined with
VARIADIC, at least for a first version of this feature, either when
defining a function or when calling one.  We can consider relaxing
that restriction at a later date if we can agree on what the semantics
should be.

This is maybe too strict. I thing, so safe version is allow variadic
packed parameter with VARIADIC keyword as Jeff proposes.

I'm working through this patch now, and I find myself not very satisfied
on the question of variadic versus named arguments. What the latest
patch actually does is:

* completely ignores variadic functions when trying to match
a call having any named arguments

* does not throw an error for use of the VARIADIC keyword
in a call together with named arguments

Neither of these behaviors quite seem to me to satisfy the principle of
least astonishment, and in combination they definitely do not.

It seems to me that there is not anything wrong with using named
arguments together with VARIADIC and getting a match to a variadic
function. VARIADIC in the argument list essentially turns off the
special behavior of variadic functions, and after that you might as
well allow either named or positional matching. (I guess if you
wanted to be really strict you'd insist that the VARIADIC keyword
be attached to the specific named argument that matches the variadic
parameter, but I don't mind being a bit lax there.)

When VARIADIC is not specified, then I think that silently ignoring
variadic functions for a named-argument call is probably reasonable.
This can be argued by imagining that the function's implicit array
element parameters do not have any names (the variadic array parameter
might have a name, but the elements generated from it do not). Since
these must be at the right end of the effective parameter list, and we
only allow named arguments at the right of the call list, there is no
way for the named arguments to match non-variadic named parameters and
still have anything matching to the variadic array elements. Therefore
a variadic function can never match such a call and ignoring it isn't
surprising.

Comments?

regards, tom lane

#36Pavel Stehule
pavel.stehule@gmail.com
In reply to: Tom Lane (#35)
Re: Issues for named/mixed function notation patch

2009/10/7 Tom Lane <tgl@sss.pgh.pa.us>:

Pavel Stehule <pavel.stehule@gmail.com> writes:

Sorry, I'm having trouble understanding what you're driving at here.
I think we should just not allow named notation to be combined with
VARIADIC, at least for a first version of this feature, either when
defining a function or when calling one.  We can consider relaxing
that restriction at a later date if we can agree on what the semantics
should be.

This is maybe too strict. I thing, so safe version is allow variadic
packed parameter with VARIADIC keyword as Jeff proposes.

I'm working through this patch now, and I find myself not very satisfied
on the question of variadic versus named arguments.  What the latest
patch actually does is:

       * completely ignores variadic functions when trying to match
         a call having any named arguments

       * does not throw an error for use of the VARIADIC keyword
         in a call together with named arguments

Neither of these behaviors quite seem to me to satisfy the principle of
least astonishment, and in combination they definitely do not.

It seems to me that there is not anything wrong with using named
arguments together with VARIADIC and getting a match to a variadic
function.  VARIADIC in the argument list essentially turns off the
special behavior of variadic functions, and after that you might as
well allow either named or positional matching.  (I guess if you
wanted to be really strict you'd insist that the VARIADIC keyword
be attached to the specific named argument that matches the variadic
parameter, but I don't mind being a bit lax there.)

When VARIADIC is not specified, then I think that silently ignoring
variadic functions for a named-argument call is probably reasonable.
This can be argued by imagining that the function's implicit array
element parameters do not have any names (the variadic array parameter
might have a name, but the elements generated from it do not).  Since
these must be at the right end of the effective parameter list, and we
only allow named arguments at the right of the call list, there is no
way for the named arguments to match non-variadic named parameters and
still have anything matching to the variadic array elements.  Therefore
a variadic function can never match such a call and ignoring it isn't
surprising.

It's same as my origin ideas, much better formulated. It is ok for me.

Pavel

Show quoted text

Comments?

                       regards, tom lane

#37Jeff Davis
pgsql@j-davis.com
In reply to: Tom Lane (#35)
Re: Issues for named/mixed function notation patch

On Wed, 2009-10-07 at 16:58 -0400, Tom Lane wrote:

* completely ignores variadic functions when trying to match
a call having any named arguments

* does not throw an error for use of the VARIADIC keyword
in a call together with named arguments

Neither of these behaviors quite seem to me to satisfy the principle of
least astonishment, and in combination they definitely do not.

I agree that the combination is wrong, and we should either allow that
call notation or throw a useful error message when it's attempted.

It seems to me that there is not anything wrong with using named
arguments together with VARIADIC and getting a match to a variadic
function.

The general feeling was that we should only support the most obvious
call notations so we wouldn't have backwards compatibility problems if
we tried to change it later.

If we allow calling a variadic function using named notation, the
VARIADIC keyword is not strictly necessary, but I think we should
require it. It seems strange without it.

Pavel indicated that there may be some implementation difficulty in
requiring the VARIADIC keyword when calling a variadic function using
named notation:

http://archives.postgresql.org/pgsql-hackers/2009-09/msg01792.php

and that just kind of pushed the idea from "maybe that's OK" to
"probably not a good idea right now".

Robert Haas weighed in here:

http://archives.postgresql.org/pgsql-hackers/2009-09/msg01732.php

Its fine with me to allow it, assuming there's a reasonable way to
implement it, and assuming that the VARIADIC keyword is required.

Regards,
Jeff Davis

#38Tom Lane
tgl@sss.pgh.pa.us
In reply to: Jeff Davis (#37)
Re: Issues for named/mixed function notation patch

Jeff Davis <pgsql@j-davis.com> writes:

If we allow calling a variadic function using named notation, the
VARIADIC keyword is not strictly necessary, but I think we should
require it. It seems strange without it.

Yeah. My first thought was to just remove the check in
FuncnameGetCandidates, which would have the effect of matching with or
without VARIADIC. It would be self-consistent but probably surprising.
But it should just be a small tweak to match only with VARIADIC.

Pavel indicated that there may be some implementation difficulty in
requiring the VARIADIC keyword when calling a variadic function using
named notation:

I think what he was considering was the question of insisting that
the VARIADIC keyword be attached to the named argument that actually
matches the VARIADIC parameter. I think we could do it, but it might
be a bit of a wart. I notice that right now, an unnecessary VARIADIC
keyword in a regular positional call does not cause an error, it's just
ignored --- so we're already being a bit lax with it.

regards, tom lane

#39Jeff Davis
pgsql@j-davis.com
In reply to: Pavel Stehule (#36)
Re: Issues for named/mixed function notation patch

On Wed, 2009-10-07 at 23:32 +0200, Pavel Stehule wrote:

It's same as my origin ideas, much better formulated. It is ok for me.

You indicated that there may be some implementation difficulty if the
VARIADIC keyword is required for calling using named notation:

http://archives.postgresql.org/pgsql-hackers/2009-09/msg01792.php

Do you think it would be reasonable to implement?

Regards,
Jeff Davis

#40Jeff Davis
pgsql@j-davis.com
In reply to: Tom Lane (#38)
Re: Issues for named/mixed function notation patch

On Wed, 2009-10-07 at 17:45 -0400, Tom Lane wrote:

I think what he was considering was the question of insisting that
the VARIADIC keyword be attached to the named argument that actually
matches the VARIADIC parameter. I think we could do it, but it might
be a bit of a wart. I notice that right now, an unnecessary VARIADIC
keyword in a regular positional call does not cause an error, it's just
ignored --- so we're already being a bit lax with it.

From a semantic standpoint, I lean towards requiring the VARIADIC

keyword consistently between named and positional notation.

It seems strange to me if we have a situation where changing the call:

foo(a, b, VARIADIC c)

to be more explicit by using named call notation:

foo(a AS x, b AS y, VARIADIC c AS z)

is "less correct" in the sense that the VARIADIC keyword goes from
"required" to "ignored".

Also, requiring VARIADIC seems to guard us better against future
changes, which seemed like a concern before.

I don't have a strong opinion or a specific problem with making VARIADIC
optional, so it's OK with me.

Regards,
Jeff Davis

#41Tom Lane
tgl@sss.pgh.pa.us
In reply to: Jeff Davis (#40)
Re: Issues for named/mixed function notation patch

Jeff Davis <pgsql@j-davis.com> writes:

On Wed, 2009-10-07 at 17:45 -0400, Tom Lane wrote:

I think what he was considering was the question of insisting that
the VARIADIC keyword be attached to the named argument that actually
matches the VARIADIC parameter.

It seems strange to me if we have a situation where changing the call:
foo(a, b, VARIADIC c)
to be more explicit by using named call notation:
foo(a AS x, b AS y, VARIADIC c AS z)
is "less correct" in the sense that the VARIADIC keyword goes from
"required" to "ignored".

No, that's not what I'm driving at. The small change that I've got in
mind would require you to say VARIADIC, but it would allow the function
to match both the above call and
foo(a AS x, c AS z, VARIADIC b AS y)
when really z is the variadic parameter in this case. I'm not sure if
this would bother anyone or not. It seems impossible that a function
could ever have more than one variadic parameter, so there's not really
any ambiguity from maintaining the syntactic rule that the VARIADIC
keyword is at the end even when the variadic argument isn't, but it
might look a bit odd.

What I *don't* want to do is fix this by allowing/requiring
foo(a AS x, VARIADIC c AS z, b AS y)
because it would be a bigger change in the grammar output structure than
seems warranted. We could possibly have VARIADIC throw an error if the
named argument that matches to the variadic parameter isn't the last
one, but I'm not sure that that's important rather than just pedantry.
People would probably tend to write it that way anyway.

regards, tom lane

#42Pavel Stehule
pavel.stehule@gmail.com
In reply to: Tom Lane (#41)
Re: Issues for named/mixed function notation patch

2009/10/8 Tom Lane <tgl@sss.pgh.pa.us>:

Jeff Davis <pgsql@j-davis.com> writes:

On Wed, 2009-10-07 at 17:45 -0400, Tom Lane wrote:

I think what he was considering was the question of insisting that
the VARIADIC keyword be attached to the named argument that actually
matches the VARIADIC parameter.

It seems strange to me if we have a situation where changing the call:
  foo(a, b, VARIADIC c)
to be more explicit by using named call notation:
  foo(a AS x, b AS y, VARIADIC c AS z)
is "less correct" in the sense that the VARIADIC keyword goes from
"required" to "ignored".

No, that's not what I'm driving at.  The small change that I've got in
mind would require you to say VARIADIC, but it would allow the function
to match both the above call and
   foo(a AS x, c AS z, VARIADIC b AS y)
when really z is the variadic parameter in this case.  I'm not sure if
this would bother anyone or not.  It seems impossible that a function
could ever have more than one variadic parameter, so there's not really
any ambiguity from maintaining the syntactic rule that the VARIADIC
keyword is at the end even when the variadic argument isn't, but it
might look a bit odd.

What I *don't* want to do is fix this by allowing/requiring
   foo(a AS x, VARIADIC c AS z, b AS y)
because it would be a bigger change in the grammar output structure than
seems warranted.  We could possibly have VARIADIC throw an error if the
named argument that matches to the variadic parameter isn't the last
one, but I'm not sure that that's important rather than just pedantry.
People would probably tend to write it that way anyway.

It is just pedantry. Position in named notation isn't important, and
there are no reason, why we VARIADIC should be last.

Pavel

Show quoted text

                       regards, tom lane

#43Pavel Stehule
pavel.stehule@gmail.com
In reply to: Jeff Davis (#39)
Re: Issues for named/mixed function notation patch

2009/10/7 Jeff Davis <pgsql@j-davis.com>:

On Wed, 2009-10-07 at 23:32 +0200, Pavel Stehule wrote:

It's same as my origin ideas, much better formulated. It is ok for me.

You indicated that there may be some implementation difficulty if the
VARIADIC keyword is required for calling using named notation:

http://archives.postgresql.org/pgsql-hackers/2009-09/msg01792.php

Do you think it would be reasonable to implement?

I thing, so this is possible. But it needs some instructions more. I
would not add some "unnecessary" checks. It needs one cycle over
parameters more (and one array).

* check if last variadic parameter isn't default
* check if last variadic parameter has flag VARIADIC
* check if there are not any other parameter with VARIADIC flag
* some correction in gram.y (procedural code), that allows VARIADIC in
any position when named notation is active.

Pavel

Show quoted text

Regards,
       Jeff Davis

#44Jeff Davis
pgsql@j-davis.com
In reply to: Tom Lane (#41)
Re: Issues for named/mixed function notation patch

On Wed, 2009-10-07 at 18:17 -0400, Tom Lane wrote:

No, that's not what I'm driving at. The small change that I've got in
mind would require you to say VARIADIC, but it would allow the function
to match both the above call and
foo(a AS x, c AS z, VARIADIC b AS y)
when really z is the variadic parameter in this case. I'm not sure if
this would bother anyone or not. It seems impossible that a function
could ever have more than one variadic parameter, so there's not really
any ambiguity from maintaining the syntactic rule that the VARIADIC
keyword is at the end even when the variadic argument isn't, but it
might look a bit odd.

I'm worried about allowing such strange notation. Someone might have a
new idea later that conflicts with it, and then we have a
backwards-compatibility problem.

What I *don't* want to do is fix this by allowing/requiring
foo(a AS x, VARIADIC c AS z, b AS y)
because it would be a bigger change in the grammar output structure than
seems warranted.

If it's the "right" thing to do (or might be the right thing to do),
someone will want to do that later, and that would be incompatible with
the:

foo(a AS x, c AS z, VARIADIC b AS y)

notation (where z is the variadic parameter).

We could possibly have VARIADIC throw an error if the
named argument that matches to the variadic parameter isn't the last
one, but I'm not sure that that's important rather than just pedantry.

I would prefer such a restriction if it's reasonable to do.

Regards,
Jeff Davis

#45Robert Haas
robertmhaas@gmail.com
In reply to: Tom Lane (#38)
Re: Issues for named/mixed function notation patch

On Wed, Oct 7, 2009 at 5:45 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

I think what he was considering was the question of insisting that
the VARIADIC keyword be attached to the named argument that actually
matches the VARIADIC parameter.  I think we could do it, but it might
be a bit of a wart.  I notice that right now, an unnecessary VARIADIC
keyword in a regular positional call does not cause an error, it's just
ignored --- so we're already being a bit lax with it.

I'd be more inclined to to tighten up the place where we're currently
being lax than to treat additional situations in a similarly lax
manner.

...Robert

#46Tom Lane
tgl@sss.pgh.pa.us
In reply to: Jeff Davis (#44)
Re: Issues for named/mixed function notation patch

Jeff Davis <pgsql@j-davis.com> writes:

We could possibly have VARIADIC throw an error if the
named argument that matches to the variadic parameter isn't the last
one, but I'm not sure that that's important rather than just pedantry.

I would prefer such a restriction if it's reasonable to do.

[ pokes around ... ] It seems to only take a few more lines, so will
do.

regards, tom lane

#47Tom Lane
tgl@sss.pgh.pa.us
In reply to: Pavel Stehule (#33)
Re: Issues for named/mixed function notation patch

Pavel Stehule <pavel.stehule@gmail.com> writes:

[ latest named-args patch ]

Committed with a fair amount of corner-case cleanup and refactoring.

regards, tom lane

#48Pavel Stehule
pavel.stehule@gmail.com
In reply to: Tom Lane (#47)
Re: Issues for named/mixed function notation patch

2009/10/8 Tom Lane <tgl@sss.pgh.pa.us>:

Pavel Stehule <pavel.stehule@gmail.com> writes:

[ latest named-args patch ]

Committed with a fair amount of corner-case cleanup and refactoring.

                       regards, tom lane

Thank you

Pavel Stehule

#49Steve Prentice
prentice@cisco.com
In reply to: Tom Lane (#47)
Re: Issues for named/mixed function notation patch

On Oct 7, 2009, at 7:41 PM, Tom Lane wrote:

Pavel Stehule <pavel.stehule@gmail.com> writes:

[ latest named-args patch ]

Committed with a fair amount of corner-case cleanup and refactoring.

Woot! Thanks for all the hard work getting this committed (Pavel,
Bernd, Jeff, Tom and others)! I've been really looking forward to this
feature. Still hoping a solution is found to the plpgsql parser issue.
If not, I'll have to resubmit my rejected AS patch. :)

-Steve

#50David E. Wheeler
david@kineticode.com
In reply to: Steve Prentice (#49)
Re: Issues for named/mixed function notation patch

On Oct 7, 2009, at 9:00 PM, Steve Prentice wrote:

Committed with a fair amount of corner-case cleanup and refactoring.

Woot! Thanks for all the hard work getting this committed (Pavel,
Bernd, Jeff, Tom and others)! I've been really looking forward to
this feature. Still hoping a solution is found to the plpgsql parser
issue. If not, I'll have to resubmit my rejected AS patch. :)

+1 Thanks for getting this done.

Now, does this just apply to PL/pgSQL? If so, what needs to happen for
other PLs to support the feature?

Best,

David

#51Jeff Davis
pgsql@j-davis.com
In reply to: David E. Wheeler (#50)
Re: Issues for named/mixed function notation patch

On Thu, 2009-10-08 at 09:44 -0700, David E. Wheeler wrote:

+1 Thanks for getting this done.

Now, does this just apply to PL/pgSQL? If so, what needs to happen for
other PLs to support the feature?

It's just the call notation -- the function only needs to know what
arguments it got for which parameters.

Regards,
Jeff Davis

#52David E. Wheeler
david@kineticode.com
In reply to: Jeff Davis (#51)
Re: Issues for named/mixed function notation patch

On Oct 8, 2009, at 9:47 AM, Jeff Davis wrote:

It's just the call notation -- the function only needs to know what
arguments it got for which parameters.

So they're still ordered? I'm thinking of PL/Perl here…

David

#53Tom Lane
tgl@sss.pgh.pa.us
In reply to: David E. Wheeler (#52)
Re: Issues for named/mixed function notation patch

"David E. Wheeler" <david@kineticode.com> writes:

On Oct 8, 2009, at 9:47 AM, Jeff Davis wrote:

It's just the call notation -- the function only needs to know what
arguments it got for which parameters.

So they're still ordered? I'm thinking of PL/Perl here�

It's PL-independent as far as I know --- if you find something where it
doesn't work, that's a bug.

regards, tom lane

#54Pavel Stehule
pavel.stehule@gmail.com
In reply to: David E. Wheeler (#50)
Re: Issues for named/mixed function notation patch

2009/10/8 David E. Wheeler <david@kineticode.com>:

On Oct 7, 2009, at 9:00 PM, Steve Prentice wrote:

Committed with a fair amount of corner-case cleanup and refactoring.

Woot! Thanks for all the hard work getting this committed (Pavel, Bernd,
Jeff, Tom and others)! I've been really looking forward to this feature.
Still hoping a solution is found to the plpgsql parser issue. If not, I'll
have to resubmit my rejected AS patch. :)

+1 Thanks for getting this done.

Now, does this just apply to PL/pgSQL? If so, what needs to happen for other
PLs to support the feature?

For other PL is named notation transparent (like defaults). Problem is
only with PL/pgSQL. I spend some time with integration main SQL parser
to PL/pgSQL and this is little bit worse then I thougs. The code is
more ugly - we have to swith between two lexers and problem is with
$1.x elements. I hope, so I'll send patch to next commitfest. Then we
can choise between Steve's patch or my patch.

Pavel

Show quoted text

Best,

David

#55Bruce Momjian
bruce@momjian.us
In reply to: Jeff Davis (#17)
Re: Issues for named/mixed function notation patch

Can someone work on a patch to implement the document changes suggested
below?

---------------------------------------------------------------------------

Jeff Davis wrote:

On Tue, 2009-09-15 at 10:51 +0200, Pavel Stehule wrote:

My renonc, please, try new patch. I forgot mark regproc.c file.

I think the documentation around calling functions is disorganized:

Variadic functions, functions with defaults, SRFs, out parameters, and
polymorphism are all explained in 34.4, which is about SQL functions
specifically.

Overloading is in chapter 34 also, but not specifically in the SQL
function section like the rest.

Function calls themselves are only given 5 lines of explanation in
4.2.6, with no mention of things like the VARIADIC keyword.

These complaints aren't about the patch, but we might want to consider
some reorganization of those sections (probably a separate doc patch).

The interaction with variadic functions appears to be misdocumented.

From the code and tests, the VARIADIC keyword appears to be optional

when using named notation, but required when using positional notation.
But the documentation says:

"However, a named variadic argument can only be called the way shown in
the example above. The VARIADIC keyword must not be specified and a
variadic notation of all arguments is not supported. To use variadic
argument lists you must use positional notation instead."

What is the intended behavior? I think we should always require VARIADIC
to be specified regardless of using named notation.

I'm still reviewing the code.

Regards,
Jeff Davis

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

-- 
  Bruce Momjian  <bruce@momjian.us>        http://momjian.us
  EnterpriseDB                             http://enterprisedb.com
  PG East:  http://www.enterprisedb.com/community/nav-pg-east-2010.do
  + If your life is a hard drive, Christ can be your backup. +
#56Pavel Stehule
pavel.stehule@gmail.com
In reply to: Bruce Momjian (#55)
Re: Issues for named/mixed function notation patch

2010/2/23 Bruce Momjian <bruce@momjian.us>:

Can someone work on a patch to implement the document changes suggested
below?

This patch is useless now. There are no this issue now, because we
have integrated true SQL parser.

Regards
Pavel

Show quoted text

---------------------------------------------------------------------------

Jeff Davis wrote:

On Tue, 2009-09-15 at 10:51 +0200, Pavel Stehule wrote:

My renonc, please, try new patch. I forgot mark regproc.c file.

I think the documentation around calling functions is disorganized:

Variadic functions, functions with defaults, SRFs, out parameters, and
polymorphism are all explained in 34.4, which is about SQL functions
specifically.

Overloading is in chapter 34 also, but not specifically in the SQL
function section like the rest.

Function calls themselves are only given 5 lines of explanation in
4.2.6, with no mention of things like the VARIADIC keyword.

These complaints aren't about the patch, but we might want to consider
some reorganization of those sections (probably a separate doc patch).

The interaction with variadic functions appears to be misdocumented.

From the code and tests, the VARIADIC keyword appears to be optional

when using named notation, but required when using positional notation.
But the documentation says:

"However, a named variadic argument can only be called the way shown in
the example above. The VARIADIC keyword must not be specified and a
variadic notation of all arguments is not supported. To use variadic
argument lists you must use positional notation instead."

What is the intended behavior? I think we should always require VARIADIC
to be specified regardless of using named notation.

I'm still reviewing the code.

Regards,
      Jeff Davis

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

--
 Bruce Momjian  <bruce@momjian.us>        http://momjian.us
 EnterpriseDB                             http://enterprisedb.com
 PG East:  http://www.enterprisedb.com/community/nav-pg-east-2010.do
 + If your life is a hard drive, Christ can be your backup. +

#57Bruce Momjian
bruce@momjian.us
In reply to: Pavel Stehule (#56)
Re: Issues for named/mixed function notation patch

Pavel Stehule wrote:

2010/2/23 Bruce Momjian <bruce@momjian.us>:

Can someone work on a patch to implement the document changes suggested
below?

This patch is useless now. There are no this issue now, because we
have integrated true SQL parser.

Great, thanks.

-- 
  Bruce Momjian  <bruce@momjian.us>        http://momjian.us
  EnterpriseDB                             http://enterprisedb.com
  PG East:  http://www.enterprisedb.com/community/nav-pg-east-2010.do
  + If your life is a hard drive, Christ can be your backup. +
#58Jeff Davis
pgsql@j-davis.com
In reply to: Bruce Momjian (#57)
Re: Issues for named/mixed function notation patch

On Tue, 2010-02-23 at 09:34 -0500, Bruce Momjian wrote:

Pavel Stehule wrote:

2010/2/23 Bruce Momjian <bruce@momjian.us>:

Can someone work on a patch to implement the document changes suggested
below?

This patch is useless now. There are no this issue now, because we
have integrated true SQL parser.

Great, thanks.

I believe a documentation issue still exists here. The section on
calling functions (4.3) still says nothing about VARIADIC. Also, it's
not 100% clear to me where function overloading should go, but perhaps
it should be mentioned in that section as well.

Regards,
Jeff Davis

#59Pavel Stehule
pavel.stehule@gmail.com
In reply to: Jeff Davis (#58)
Re: Issues for named/mixed function notation patch

2010/2/24 Jeff Davis <pgsql@j-davis.com>:

On Tue, 2010-02-23 at 09:34 -0500, Bruce Momjian wrote:

Pavel Stehule wrote:

2010/2/23 Bruce Momjian <bruce@momjian.us>:

Can someone work on a patch to implement the document changes suggested
below?

This patch is useless now. There are no this issue now, because we
have integrated true SQL parser.

Great, thanks.

I believe a documentation issue still exists here. The section on
calling functions (4.3) still says nothing about VARIADIC. Also, it's
not 100% clear to me where function overloading should go, but perhaps
it should be mentioned in that section as well.

please, can you write patch. For me it is mession impossible :)

Pavel

Show quoted text

Regards,
       Jeff Davis