*** ./doc/src/sgml/xfunc.sgml.orig 2009-03-05 07:37:10.000000000 +0100
--- ./doc/src/sgml/xfunc.sgml 2009-03-05 08:30:48.000000000 +0100
***************
*** 1101,1106 ****
--- 1101,1222 ----
+
+ Positional, Mixed and Named notation
+
+
+ notation
+ functions
+
+
+
+ Functions with named parameters should by called with mixed
+ or named notation. Any typical use expects posiotional
+ notation, when an order of parameters is important. For named notation
+ is important name of parameters. You can mix both notation - result is mixed notation.
+ Some first n parameters should be entered in positional parameters
+ and others in named notation. You don't need pass parameters than has
+ default value.
+
+ CREATE FUNCTION fx(a int, b int, m int = 1, o int = 0) RETURNS int AS $$
+ SELECT ($1 + $2) * $3 + $4
+ $$ LANGUAGE SQL;
+
+ Function fx has obligatory parameters: a and
+ b and optional parameters: m and o.
+ This function should be called with positional parameters. See for a more detailed explanation of calling
+ function with default values.
+
+
+
+ Using positional notation
+
+
+ function
+ positional notation
+
+
+
+
+ SELECT fx(10,20);
+ fx
+ ----
+ 30
+ (1 row)
+
+ SELECT fx(10,20,2,50);
+ fx
+ -----
+ 110
+ (1 row)
+
+
+
+
+
+ Using named notation
+
+
+ function
+ named notation
+
+
+
+
+ SELECT fx(10 as a, 20 as b);
+ fx
+ ----
+ 30
+ (1 row)
+
+ SELECT fx(20 as b, 10 as a);
+ fx
+ ----
+ 30
+ (1 row)
+
+ SELECT fx(20 as b, 10 as a, 50 as o);
+ fx
+ ----
+ 80
+ (1 row)
+
+
+
+
+
+ Using mixed notation
+
+
+ function
+ mixed notation
+
+
+
+
+ SELECT fx(10,20, 50 as o);
+ fx
+ ----
+ 80
+ (1 row)
+
+ SELECT fx(10,20, 10 as m);
+ fx
+ -----
+ 300
+ (1 row)
+
+ SELECT fx(10,20, 50 as o, 2 as m);
+ fx
+ -----
+ 110
+ (1 row)
+
+
+
+
+
Function Volatility Categories
*** ./src/backend/catalog/namespace.c.orig 2009-03-03 14:48:25.000000000 +0100
--- ./src/backend/catalog/namespace.c 2009-03-04 18:31:20.000000000 +0100
***************
*** 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"
***************
*** 603,610 ****
* The caller might end up discarding such an entry anyway, but if it selects
* such an entry it should react as though the call were ambiguous.
*/
FuncCandidateList
! FuncnameGetCandidates(List *names, int nargs,
bool expand_variadic, bool expand_defaults)
{
FuncCandidateList resultList = NULL;
--- 604,723 ----
* The caller might end up discarding such an entry anyway, but if it selects
* such an entry it should react as though the call were ambiguous.
*/
+ static bool
+ VerifyCandidateNamedNotation(HeapTuple proctup, int pronargs, int nargs, List *argnames, short int pronargdefaults,
+ bool *use_defaults, short int **param_map)
+ {
+ Datum proargnames;
+ Oid *p_argtypes;
+ char **p_argnames;
+ char *p_argmodes;
+ bool isnull;
+ int pronallargs;
+ int i;
+ int pp; /* proargs position */
+ int ap; /* args position */
+ ListCell *lc;
+ FuncCallNotation used_notation = POSITIONAL_NOTATION; /* used only for asertion */
+
+ #define UNDEFINED_PARAMETER -1
+
+ Assert(argnames != NIL);
+
+ /* Ignore if not enough default expressions */
+ if (nargs + pronargdefaults < pronargs)
+ return false;
+
+ /* check proargnames */
+ proargnames = SysCacheGetAttr(PROCOID, proctup,
+ Anum_pg_proc_proargnames,
+ &isnull);
+ if (isnull)
+ return false;
+
+ pronallargs = get_func_arg_info(proctup, &p_argtypes, &p_argnames, &p_argmodes);
+ Assert(p_argnames != NULL);
+
+ /*
+ * An number less or equal nargs means some arg,
+ * an number greather than nargs means some default.
+ */
+ *param_map = palloc(pronargs * sizeof(short int));
+ for (i = 0; i < pronargs; i++)
+ (*param_map)[i] = UNDEFINED_PARAMETER;
+
+ ap = 0;
+ foreach(lc, argnames)
+ {
+ char *argname = (char *) lfirst(lc);
+ bool found;
+
+ if (argname != NULL)
+ {
+ pp = 0;
+ found = false;
+ for (i = 0; i < pronallargs; i++)
+ {
+ /* skip all out params */
+ if (p_argmodes && (p_argmodes[i] != FUNC_PARAM_IN && p_argmodes[i] != FUNC_PARAM_INOUT))
+ continue;
+ if (p_argnames[i] && strcmp(p_argnames[i], argname) == 0)
+ {
+ /* protect under twice entry same param via positional and named notation */
+ if ((*param_map)[pp] != UNDEFINED_PARAMETER)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("named parameter \"%s\" overlaps %d. positional parameter", argname, i + 1)));
+
+ found = true;
+ (*param_map)[pp] = ap; /* named parameter */
+ break;
+ }
+ /* increase only for IN and INOUT args */
+ pp++;
+ }
+ /* any name isn't in proargnames, fast leaving */
+ if (!found)
+ return false;
+
+ used_notation = NAMED_NOTATION;
+ }
+ else
+ {
+ Assert(used_notation == POSITIONAL_NOTATION);
+
+ (*param_map)[ap] = ap; /* positional parameter */
+ }
+ ap++;
+ }
+
+ Assert(used_notation == NAMED_NOTATION);
+
+ /* Have we check defaults? */
+ if (nargs < pronargs)
+ {
+ int first_arg_with_default = pronargs - pronargdefaults;
+
+ for (i = 0; i < pronargs; i++)
+ {
+ /* When we still missing param and no default is available, exit */
+ if ((*param_map)[i] == UNDEFINED_PARAMETER)
+ {
+ if (i < first_arg_with_default)
+ return false;
+ /* offset to defaults + nargs */
+ (*param_map)[i] = i - first_arg_with_default + nargs;
+ }
+ }
+ *use_defaults = true;
+ }
+
+ return true;
+ }
+
+
FuncCandidateList
! FuncnameGetCandidates(List *names, int nargs, List *argnames,
bool expand_variadic, bool expand_defaults)
{
FuncCandidateList resultList = NULL;
***************
*** 645,688 ****
int pronargs = procform->pronargs;
int effective_nargs;
int pathpos = 0;
! bool variadic;
! bool use_defaults;
! Oid va_elem_type;
FuncCandidateList newResult;
! /*
! * Check if function is variadic, and get variadic element type if so.
! * If expand_variadic is false, we should just ignore variadic-ness.
! */
! if (pronargs <= nargs && expand_variadic)
{
! va_elem_type = procform->provariadic;
! variadic = OidIsValid(va_elem_type);
! any_special |= variadic;
}
else
{
! va_elem_type = InvalidOid;
! variadic = false;
! }
! /*
! * Check if function can match by using parameter defaults.
! */
! if (pronargs > nargs && expand_defaults)
! {
! /* Ignore if not enough default expressions */
! if (nargs + procform->pronargdefaults < pronargs)
continue;
- use_defaults = true;
- any_special = true;
}
- else
- use_defaults = false;
-
- /* Ignore if it doesn't match requested argument count */
- if (nargs >= 0 && pronargs != nargs && !variadic && !use_defaults)
- continue;
if (OidIsValid(namespaceId))
{
--- 758,811 ----
int pronargs = procform->pronargs;
int effective_nargs;
int pathpos = 0;
! bool variadic = false;
! bool use_defaults = false;
! Oid va_elem_type = InvalidOid;
FuncCandidateList newResult;
+ short int *param_map = NULL;
! if (argnames != NIL)
{
! if (!VerifyCandidateNamedNotation(proctup, pronargs, nargs, argnames, procform->pronargdefaults,
! &use_defaults, ¶m_map))
! continue;
}
else
{
! /*
! * Check if function is variadic, and get variadic element type if so.
! * If expand_variadic is false, we should just ignore variadic-ness.
! */
! if (pronargs <= nargs && expand_variadic)
! {
! va_elem_type = procform->provariadic;
! variadic = OidIsValid(va_elem_type);
! any_special |= variadic;
! }
! else
! {
! va_elem_type = InvalidOid;
! variadic = false;
! }
! /*
! * Check if function can match by using parameter defaults.
! */
! if (pronargs > nargs && expand_defaults)
! {
! /* Ignore if not enough default expressions */
! if (nargs + procform->pronargdefaults < pronargs)
! continue;
! use_defaults = true;
! any_special = true;
! }
! else
! use_defaults = false;
!
! /* Ignore if it doesn't match requested argument count */
! if (nargs >= 0 && pronargs != nargs && !variadic && !use_defaults)
continue;
}
if (OidIsValid(namespaceId))
{
***************
*** 722,727 ****
--- 845,851 ----
newResult->pathpos = pathpos;
newResult->oid = HeapTupleGetOid(proctup);
newResult->nargs = effective_nargs;
+ newResult->param_map = param_map;
memcpy(newResult->args, procform->proargtypes.values,
pronargs * sizeof(Oid));
if (variadic)
***************
*** 735,741 ****
}
else
newResult->nvargs = 0;
! newResult->ndargs = use_defaults ? pronargs - nargs : 0;
/*
* Does it have the same arguments as something we already accepted?
--- 859,872 ----
}
else
newResult->nvargs = 0;
! /* When named notation is used, then complete set of defaults is returned */
! if (argnames != NIL)
! {
! Assert(param_map != NULL);
! newResult->ndargs = procform->pronargdefaults;
! }
! else
! newResult->ndargs = use_defaults ? pronargs - nargs : 0;
/*
* Does it have the same arguments as something we already accepted?
***************
*** 932,938 ****
visible = false;
clist = FuncnameGetCandidates(list_make1(makeString(proname)),
! nargs, false, false);
for (; clist; clist = clist->next)
{
--- 1063,1069 ----
visible = false;
clist = FuncnameGetCandidates(list_make1(makeString(proname)),
! nargs, NIL, false, false);
for (; clist; clist = clist->next)
{
***************
*** 953,959 ****
/*
! * OpernameGetOprid
* Given a possibly-qualified operator name and exact input datatypes,
* look up the operator. Returns InvalidOid if not found.
*
--- 1084,1090 ----
/*
! * OpernameGetOpri
* Given a possibly-qualified operator name and exact input datatypes,
* look up the operator. Returns InvalidOid if not found.
*
*** ./src/backend/catalog/pg_aggregate.c.orig 2009-03-03 16:44:18.000000000 +0100
--- ./src/backend/catalog/pg_aggregate.c 2009-03-04 14:15:08.000000000 +0100
***************
*** 321,329 ****
* function's return value. it also returns the true argument types to
* the function.
*/
! fdresult = func_get_detail(fnName, NIL, nargs, input_types, false, false,
&fnOid, rettype, &retset, &nvargs,
! &true_oid_array, NULL);
/* only valid case is a normal function not returning a set */
if (fdresult != FUNCDETAIL_NORMAL || !OidIsValid(fnOid))
--- 321,329 ----
* function's return value. it also returns the true argument types to
* the function.
*/
! fdresult = func_get_detail(fnName, NIL, NIL, nargs, input_types, false, false,
&fnOid, rettype, &retset, &nvargs,
! &true_oid_array, NULL, NULL, NULL);
/* only valid case is a normal function not returning a set */
if (fdresult != FUNCDETAIL_NORMAL || !OidIsValid(fnOid))
*** ./src/backend/nodes/copyfuncs.c.orig 2009-03-03 13:11:22.000000000 +0100
--- ./src/backend/nodes/copyfuncs.c 2009-03-04 14:25:54.000000000 +0100
***************
*** 1009,1014 ****
--- 1009,1015 ----
COPY_SCALAR_FIELD(funcresulttype);
COPY_SCALAR_FIELD(funcretset);
COPY_SCALAR_FIELD(funcformat);
+ COPY_SCALAR_FIELD(argformat);
COPY_NODE_FIELD(args);
COPY_LOCATION_FIELD(location);
***************
*** 1906,1911 ****
--- 1907,1923 ----
return newnode;
}
+ static ArgExpr *
+ _copyArgExpr(ArgExpr *from)
+ {
+ ArgExpr *newnode = makeNode(ArgExpr);
+
+ COPY_STRING_FIELD(name);
+ COPY_NODE_FIELD(expr);
+
+ return newnode;
+ }
+
static A_Star *
_copyAStar(A_Star *from)
{
***************
*** 4026,4031 ****
--- 4038,4046 ----
case T_FuncCall:
retval = _copyFuncCall(from);
break;
+ case T_ArgExpr:
+ retval = _copyArgExpr(from);
+ break;
case T_A_Star:
retval = _copyAStar(from);
break;
*** ./src/backend/nodes/equalfuncs.c.orig 2009-03-04 14:28:58.000000000 +0100
--- ./src/backend/nodes/equalfuncs.c 2009-03-04 14:31:26.000000000 +0100
***************
*** 235,240 ****
--- 235,241 ----
b->funcformat != COERCE_DONTCARE)
return false;
+ COMPARE_SCALAR_FIELD(argformat);
COMPARE_NODE_FIELD(args);
COMPARE_LOCATION_FIELD(location);
*** ./src/backend/nodes/makefuncs.c.orig 2009-03-04 14:26:40.000000000 +0100
--- ./src/backend/nodes/makefuncs.c 2009-03-04 14:27:54.000000000 +0100
***************
*** 342,347 ****
--- 342,348 ----
funcexpr->funcresulttype = rettype;
funcexpr->funcretset = false; /* only allowed case here */
funcexpr->funcformat = fformat;
+ funcexpr->argformat = CONTINUOUS_LIST;
funcexpr->args = args;
funcexpr->location = -1;
*** ./src/backend/nodes/outfuncs.c.orig 2009-03-03 13:11:23.000000000 +0100
--- ./src/backend/nodes/outfuncs.c 2009-03-04 14:31:06.000000000 +0100
***************
*** 866,871 ****
--- 866,872 ----
WRITE_OID_FIELD(funcresulttype);
WRITE_BOOL_FIELD(funcretset);
WRITE_ENUM_FIELD(funcformat, CoercionForm);
+ WRITE_ENUM_FIELD(argformat, ArgumentForm);
WRITE_NODE_FIELD(args);
WRITE_LOCATION_FIELD(location);
}
***************
*** 1786,1791 ****
--- 1787,1801 ----
}
static void
+ _outArgExpr(StringInfo str, ArgExpr *node)
+ {
+ WRITE_NODE_TYPE("ARGEXPR");
+
+ WRITE_STRING_FIELD(name);
+ WRITE_NODE_FIELD(expr);
+ }
+
+ static void
_outDefElem(StringInfo str, DefElem *node)
{
WRITE_NODE_TYPE("DEFELEM");
***************
*** 2764,2769 ****
--- 2774,2782 ----
case T_FuncCall:
_outFuncCall(str, obj);
break;
+ case T_ArgExpr:
+ _outArgExpr(str, obj);
+ break;
case T_DefElem:
_outDefElem(str, obj);
break;
*** ./src/backend/nodes/readfuncs.c.orig 2009-03-04 14:29:23.000000000 +0100
--- ./src/backend/nodes/readfuncs.c 2009-03-04 14:32:00.000000000 +0100
***************
*** 518,523 ****
--- 518,524 ----
READ_OID_FIELD(funcresulttype);
READ_BOOL_FIELD(funcretset);
READ_ENUM_FIELD(funcformat, CoercionForm);
+ READ_ENUM_FIELD(argformat, ArgumentForm);
READ_NODE_FIELD(args);
READ_LOCATION_FIELD(location);
*** ./src/backend/optimizer/util/clauses.c.orig 2009-03-04 14:21:48.000000000 +0100
--- ./src/backend/optimizer/util/clauses.c 2009-03-04 17:58:19.000000000 +0100
***************
*** 94,103 ****
bool *haveNull, bool *forceFalse);
static Expr *simplify_boolean_equality(List *args);
static Expr *simplify_function(Oid funcid,
! Oid result_type, int32 result_typmod, List **args,
bool allow_inline,
eval_const_expressions_context *context);
! static List *add_function_defaults(List *args, Oid result_type,
HeapTuple func_tuple,
eval_const_expressions_context *context);
static Expr *evaluate_function(Oid funcid,
--- 94,104 ----
bool *haveNull, bool *forceFalse);
static Expr *simplify_boolean_equality(List *args);
static Expr *simplify_function(Oid funcid,
! Oid result_type, int32 result_typmod,
! List **args, bool leaky_list,
bool allow_inline,
eval_const_expressions_context *context);
! static List *add_function_defaults(List *args, bool leaky_list, Oid result_type,
HeapTuple func_tuple,
eval_const_expressions_context *context);
static Expr *evaluate_function(Oid funcid,
***************
*** 2132,2138 ****
*/
simple = simplify_function(expr->funcid,
expr->funcresulttype, exprTypmod(node),
! &args,
true, context);
if (simple) /* successfully simplified it */
return (Node *) simple;
--- 2133,2139 ----
*/
simple = simplify_function(expr->funcid,
expr->funcresulttype, exprTypmod(node),
! &args, expr->argformat == LEAKY_LIST,
true, context);
if (simple) /* successfully simplified it */
return (Node *) simple;
***************
*** 2147,2152 ****
--- 2148,2154 ----
newexpr->funcresulttype = expr->funcresulttype;
newexpr->funcretset = expr->funcretset;
newexpr->funcformat = expr->funcformat;
+ newexpr->argformat = expr->argformat;
newexpr->args = args;
newexpr->location = expr->location;
return (Node *) newexpr;
***************
*** 2179,2185 ****
*/
simple = simplify_function(expr->opfuncid,
expr->opresulttype, -1,
! &args,
true, context);
if (simple) /* successfully simplified it */
return (Node *) simple;
--- 2181,2187 ----
*/
simple = simplify_function(expr->opfuncid,
expr->opresulttype, -1,
! &args, false,
true, context);
if (simple) /* successfully simplified it */
return (Node *) simple;
***************
*** 2270,2276 ****
*/
simple = simplify_function(expr->opfuncid,
expr->opresulttype, -1,
! &args,
false, context);
if (simple) /* successfully simplified it */
{
--- 2272,2278 ----
*/
simple = simplify_function(expr->opfuncid,
expr->opresulttype, -1,
! &args, false,
false, context);
if (simple) /* successfully simplified it */
{
***************
*** 2462,2468 ****
simple = simplify_function(outfunc,
CSTRINGOID, -1,
! &args,
true, context);
if (simple) /* successfully simplified output fn */
{
--- 2464,2470 ----
simple = simplify_function(outfunc,
CSTRINGOID, -1,
! &args, false,
true, context);
if (simple) /* successfully simplified output fn */
{
***************
*** 2480,2486 ****
simple = simplify_function(infunc,
expr->resulttype, -1,
! &args,
true, context);
if (simple) /* successfully simplified input fn */
return (Node *) simple;
--- 2482,2488 ----
simple = simplify_function(infunc,
expr->resulttype, -1,
! &args, false,
true, context);
if (simple) /* successfully simplified input fn */
return (Node *) simple;
***************
*** 3225,3230 ****
--- 3227,3233 ----
static Expr *
simplify_function(Oid funcid, Oid result_type, int32 result_typmod,
List **args,
+ bool leaky_list,
bool allow_inline,
eval_const_expressions_context *context)
{
***************
*** 3246,3253 ****
elog(ERROR, "cache lookup failed for function %u", funcid);
/* While we have the tuple, check if we need to add defaults */
! if (((Form_pg_proc) GETSTRUCT(func_tuple))->pronargs > list_length(*args))
! *args = add_function_defaults(*args, result_type, func_tuple, context);
newexpr = evaluate_function(funcid, result_type, result_typmod, *args,
func_tuple, context);
--- 3249,3256 ----
elog(ERROR, "cache lookup failed for function %u", funcid);
/* While we have the tuple, check if we need to add defaults */
! if (((Form_pg_proc) GETSTRUCT(func_tuple))->pronargs > list_length(*args) || leaky_list)
! *args = add_function_defaults(*args, leaky_list, result_type, func_tuple, context);
newexpr = evaluate_function(funcid, result_type, result_typmod, *args,
func_tuple, context);
***************
*** 3270,3276 ****
* just like the parser did.
*/
static List *
! add_function_defaults(List *args, Oid result_type, HeapTuple func_tuple,
eval_const_expressions_context *context)
{
Form_pg_proc funcform = (Form_pg_proc) GETSTRUCT(func_tuple);
--- 3273,3279 ----
* just like the parser did.
*/
static List *
! add_function_defaults(List *args, bool leaky_list, Oid result_type, HeapTuple func_tuple,
eval_const_expressions_context *context)
{
Form_pg_proc funcform = (Form_pg_proc) GETSTRUCT(func_tuple);
***************
*** 3296,3309 ****
defaults = (List *) stringToNode(str);
Assert(IsA(defaults, List));
pfree(str);
! /* Delete any unused defaults from the list */
! ndelete = nargsprovided + list_length(defaults) - funcform->pronargs;
! if (ndelete < 0)
! elog(ERROR, "not enough default arguments");
! while (ndelete-- > 0)
! defaults = list_delete_first(defaults);
! /* And form the combined argument list */
! args = list_concat(args, defaults);
Assert(list_length(args) == funcform->pronargs);
/*
--- 3299,3339 ----
defaults = (List *) stringToNode(str);
Assert(IsA(defaults, List));
pfree(str);
!
! if (leaky_list)
! {
! List *cargs = NIL; /* continuous argument list */
! ListCell *lc;
! int i = 0;
! bool first_default = funcform->pronargs - funcform->pronargdefaults;
!
! /* Replace gaps with elements from defaults */
! foreach(lc, args)
! {
! Node *arg = (Node *) lfirst(lc);
!
! if (arg == NULL)
! {
! Assert(i >= first_default);
! cargs = lappend(cargs, list_nth(defaults, i - first_default));
! }
! else
! cargs = lappend(cargs, arg);
! i++;
! }
! args = cargs;
! }
! else
! {
! /* Delete any unused defaults from the list */
! ndelete = nargsprovided + list_length(defaults) - funcform->pronargs;
! if (ndelete < 0)
! elog(ERROR, "not enough default arguments");
! while (ndelete-- > 0)
! defaults = list_delete_first(defaults);
! /* And form the combined argument list */
! args = list_concat(args, defaults);
! }
Assert(list_length(args) == funcform->pronargs);
/*
***************
*** 3442,3447 ****
--- 3472,3478 ----
newexpr->funcresulttype = result_type;
newexpr->funcretset = false;
newexpr->funcformat = COERCE_DONTCARE; /* doesn't matter */
+ newexpr->funcformat = CONTINUOUS_LIST;
newexpr->args = args;
newexpr->location = -1;
*** ./src/backend/parser/gram.y.orig 2009-02-24 11:06:33.000000000 +0100
--- ./src/backend/parser/gram.y 2009-03-03 13:08:21.000000000 +0100
***************
*** 420,425 ****
--- 420,428 ----
%type opt_existing_window_name
%type opt_frame_clause frame_extent frame_bound
+ %type arg_expr_list
+ %type arg_expr
+
/*
* If you make any token changes, update the keyword table in
***************
*** 8776,8782 ****
n->location = @1;
$$ = (Node *)n;
}
! | func_name '(' expr_list ')' over_clause
{
FuncCall *n = makeNode(FuncCall);
n->funcname = $1;
--- 8779,8785 ----
n->location = @1;
$$ = (Node *)n;
}
! | func_name '(' arg_expr_list ')' over_clause
{
FuncCall *n = makeNode(FuncCall);
n->funcname = $1;
***************
*** 8800,8806 ****
n->location = @1;
$$ = (Node *)n;
}
! | func_name '(' expr_list ',' VARIADIC a_expr ')' over_clause
{
FuncCall *n = makeNode(FuncCall);
n->funcname = $1;
--- 8803,8809 ----
n->location = @1;
$$ = (Node *)n;
}
! | func_name '(' arg_expr_list ',' VARIADIC a_expr ')' over_clause
{
FuncCall *n = makeNode(FuncCall);
n->funcname = $1;
***************
*** 8812,8818 ****
n->location = @1;
$$ = (Node *)n;
}
! | func_name '(' ALL expr_list ')' over_clause
{
FuncCall *n = makeNode(FuncCall);
n->funcname = $1;
--- 8815,8821 ----
n->location = @1;
$$ = (Node *)n;
}
! | func_name '(' ALL arg_expr_list ')' over_clause
{
FuncCall *n = makeNode(FuncCall);
n->funcname = $1;
***************
*** 8828,8834 ****
n->location = @1;
$$ = (Node *)n;
}
! | func_name '(' DISTINCT expr_list ')' over_clause
{
FuncCall *n = makeNode(FuncCall);
n->funcname = $1;
--- 8831,8837 ----
n->location = @1;
$$ = (Node *)n;
}
! | func_name '(' DISTINCT arg_expr_list ')' over_clause
{
FuncCall *n = makeNode(FuncCall);
n->funcname = $1;
***************
*** 9550,9555 ****
--- 9553,9583 ----
$$ = lappend($1, $3);
}
;
+
+ /* Used for support of named notation.
+ */
+ arg_expr_list: arg_expr
+ {
+ $$ = list_make1($1);
+ }
+ | arg_expr_list ',' arg_expr
+ {
+ $$ = lappend($1, $3);
+ }
+ ;
+
+ arg_expr: a_expr
+ {
+ $$ = $1;
+ }
+ | a_expr AS param_name
+ {
+ ArgExpr *ae = makeNode(ArgExpr);
+ ae->expr = $1;
+ ae->name = $3;
+ $$ = (Node *) ae;
+ }
+ ;
type_list: Typename { $$ = list_make1($1); }
| type_list ',' Typename { $$ = lappend($1, $3); }
***************
*** 9950,9956 ****
;
! name: ColId { $$ = $1; };
database_name:
ColId { $$ = $1; };
--- 9978,9984 ----
;
! name: ColId { $$ = $1; };
database_name:
ColId { $$ = $1; };
***************
*** 9980,9986 ****
/*
! * Constants
*/
AexprConst: Iconst
{
--- 10008,10014 ----
/*
! * Constants ToDo - PStehule
*/
AexprConst: Iconst
{
***************
*** 10014,10023 ****
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);
--- 10042,10059 ----
t->location = @1;
$$ = makeStringConstCast($2, @2, t);
}
! | func_name '(' arg_expr_list ')' Sconst
{
/* generic syntax with a type modifier */
TypeName *t = makeTypeNameFromNameList($1);
+ ListCell *lc;
+
+ /* Don't allow ArgExpr in this context */
+ foreach(lc, $3)
+ {
+ if (IsA((Node *) lfirst(lc),ArgExpr))
+ elog(ERROR, "don't use named parameters in this context");
+ }
t->typmods = $3;
t->location = @1;
$$ = makeStringConstCast($5, @5, t);
*** ./src/backend/parser/parse_expr.c.orig 2009-03-03 12:56:38.000000000 +0100
--- ./src/backend/parser/parse_expr.c 2009-03-03 14:18:12.000000000 +0100
***************
*** 362,368 ****
list_make1(n),
list_make1(result),
false, false, false,
! NULL, true, -1);
}
}
/* process trailing subscripts, if any */
--- 362,368 ----
list_make1(n),
list_make1(result),
false, false, false,
! NULL, true, NIL, -1);
}
}
/* process trailing subscripts, if any */
***************
*** 506,512 ****
list_make1(makeString(name2)),
list_make1(node),
false, false, false,
! NULL, true, cref->location);
}
break;
}
--- 506,512 ----
list_make1(makeString(name2)),
list_make1(node),
false, false, false,
! NULL, true, NIL, cref->location);
}
break;
}
***************
*** 547,553 ****
list_make1(makeString(name3)),
list_make1(node),
false, false, false,
! NULL, true, cref->location);
}
break;
}
--- 547,553 ----
list_make1(makeString(name3)),
list_make1(node),
false, false, false,
! NULL, true, NIL, cref->location);
}
break;
}
***************
*** 602,608 ****
list_make1(makeString(name4)),
list_make1(node),
false, false, false,
! NULL, true, cref->location);
}
break;
}
--- 602,608 ----
list_make1(makeString(name4)),
list_make1(node),
false, false, false,
! NULL, true, NIL, cref->location);
}
break;
}
***************
*** 1091,1107 ****
static Node *
transformFuncCall(ParseState *pstate, FuncCall *fn)
{
! List *targs;
ListCell *args;
/* Transform the list of arguments ... */
- targs = NIL;
foreach(args, fn->args)
{
! targs = lappend(targs, transformExpr(pstate,
! (Node *) lfirst(args)));
}
/* ... and hand off to ParseFuncOrColumn */
return ParseFuncOrColumn(pstate,
fn->funcname,
--- 1091,1158 ----
static Node *
transformFuncCall(ParseState *pstate, FuncCall *fn)
{
! List *targs = NIL;
ListCell *args;
+ List *argnames = NIL;
+ bool argnames_used = false;
+ FuncCallNotation notation = POSITIONAL_NOTATION;
/* Transform the list of arguments ... */
foreach(args, fn->args)
{
! char *name = NULL;
! Node *targ = NULL;
! Node *arg = lfirst(args);
!
! if (IsA(arg, ArgExpr))
! {
! ArgExpr *argexpr = (ArgExpr *) arg;
! ListCell *lc;
!
! Assert(argexpr->name != NULL);
!
! argnames_used = true;
! notation = NAMED_NOTATION;
!
! name = argexpr->name;
! targ = transformExpr(pstate, argexpr->expr);
!
! /* Check duplicates */
! for_each_cell(lc, lnext(args))
! {
! if (IsA(lfirst(lc), ArgExpr))
! {
! char *next_name = ((ArgExpr *) lfirst(lc))->name;
!
! Assert(next_name != NULL);
! if (strcmp(name, next_name) == 0)
! ereport(ERROR,
! (errcode(ERRCODE_SYNTAX_ERROR),
! errmsg("function parameter \"%s\" is used more then once", name),
! errhint("Check used names of next parameters."),
! parser_errposition(pstate, exprLocation(targ))));
! }
! }
! }
! else
! {
! targ = transformExpr(pstate, arg);
! if (notation != POSITIONAL_NOTATION)
! ereport(ERROR,
! (errcode(ERRCODE_SYNTAX_ERROR),
! errmsg("expected named expression"),
! errhint("You can't put positionals arguments behind the named arguments."),
! parser_errposition(pstate, exprLocation(targ))));
! }
!
! targs = lappend(targs, targ);
! argnames = lappend(argnames, name);
}
+ /* forgot list of NULLs */
+ if (!argnames_used)
+ argnames = NIL;
+
/* ... and hand off to ParseFuncOrColumn */
return ParseFuncOrColumn(pstate,
fn->funcname,
***************
*** 1111,1116 ****
--- 1162,1168 ----
fn->func_variadic,
fn->over,
false,
+ argnames,
fn->location);
}
***************
*** 1167,1173 ****
Node *warg;
Assert(IsA(w, CaseWhen));
-
warg = (Node *) w->expr;
if (placeholder)
{
--- 1219,1224 ----
*** ./src/backend/parser/parse_func.c.orig 2009-03-03 12:56:45.000000000 +0100
--- ./src/backend/parser/parse_func.c 2009-03-04 15:46:52.000000000 +0100
***************
*** 63,69 ****
Node *
ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
bool agg_star, bool agg_distinct, bool func_variadic,
! WindowDef *over, bool is_column, int location)
{
Oid rettype;
Oid funcid;
--- 63,69 ----
Node *
ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
bool agg_star, bool agg_distinct, bool func_variadic,
! WindowDef *over, bool is_column, List *argnames, int location)
{
Oid rettype;
Oid funcid;
***************
*** 79,84 ****
--- 79,87 ----
bool retset;
int nvargs;
FuncDetailCode fdresult;
+ short int *param_map;
+ int pronargs;
+ ArgumentForm argformat = CONTINUOUS_LIST;
/*
* Most of the rest of the parser just assumes that functions do not have
***************
*** 132,138 ****
* 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];
--- 135,141 ----
* wasn't any aggregate or variadic decoration.
*/
if (nargs == 1 && !agg_star && !agg_distinct && over == NULL &&
! !func_variadic && list_length(funcname) == 1 && argnames == NIL)
{
Oid argtype = actual_arg_types[0];
***************
*** 163,172 ****
* replaced by a suitable number of copies of its element type. We'll fix
* it up below. We may also have to deal with default arguments.
*/
! fdresult = func_get_detail(funcname, fargs, nargs, actual_arg_types,
!func_variadic, true,
&funcid, &rettype, &retset, &nvargs,
! &declared_arg_types, &argdefaults);
if (fdresult == FUNCDETAIL_COERCION)
{
/*
--- 166,175 ----
* replaced by a suitable number of copies of its element type. We'll fix
* it up below. We may also have to deal with default arguments.
*/
! fdresult = func_get_detail(funcname, fargs, argnames, nargs, actual_arg_types,
!func_variadic, true,
&funcid, &rettype, &retset, &nvargs,
! &declared_arg_types, &argdefaults, ¶m_map, &pronargs);
if (fdresult == FUNCDETAIL_COERCION)
{
/*
***************
*** 243,248 ****
--- 246,281 ----
parser_errposition(pstate, location)));
}
+
+ if (param_map != NULL)
+ {
+ List *rfargs = NIL; /* reordered list of function arguments */
+ int i;
+
+ for (i = 0; i < pronargs; i++)
+ {
+ Node *expr = NULL;
+
+ if (param_map[i] < nargs)
+ {
+ expr = (Node *) list_nth(fargs, param_map[i]);
+ rfargs = lappend(rfargs, expr);
+ /* when any arg goes out of narg */
+ if (i >= nargs)
+ argformat = LEAKY_LIST;
+ }
+ else
+ {
+ expr = (Node *) list_nth(argdefaults, param_map[i] - nargs);
+ rfargs = lappend(rfargs, NULL);
+ }
+ actual_arg_types[i] = exprType(expr);
+ }
+
+ fargs = (argformat == LEAKY_LIST) ? rfargs : list_truncate(rfargs, nargs);
+ nargsplusdefs = pronargs;
+ }
+ else
/*
* If there are default arguments, we have to include their types in
* actual_arg_types for the purpose of checking generic type consistency.
***************
*** 250,269 ****
* their actual values might change before the query gets run. The
* planner has to insert the up-to-date values at plan time.
*/
- nargsplusdefs = nargs;
- foreach(l, argdefaults)
{
! Node *expr = (Node *) lfirst(l);
! /* probably shouldn't happen ... */
! if (nargsplusdefs >= FUNC_MAX_ARGS)
! ereport(ERROR,
! (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
! errmsg("cannot pass more than %d arguments to a function",
! FUNC_MAX_ARGS),
! parser_errposition(pstate, location)));
! actual_arg_types[nargsplusdefs++] = exprType(expr);
}
/*
--- 283,304 ----
* their actual values might change before the query gets run. The
* planner has to insert the up-to-date values at plan time.
*/
{
! nargsplusdefs = nargs;
! foreach(l, argdefaults)
! {
! Node *expr = (Node *) lfirst(l);
! /* probably shouldn't happen ... */
! if (nargsplusdefs >= FUNC_MAX_ARGS)
! ereport(ERROR,
! (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
! errmsg("cannot pass more than %d arguments to a function",
! FUNC_MAX_ARGS),
! parser_errposition(pstate, location)));
! actual_arg_types[nargsplusdefs++] = exprType(expr);
! }
}
/*
***************
*** 319,324 ****
--- 354,360 ----
funcexpr->funcresulttype = rettype;
funcexpr->funcretset = retset;
funcexpr->funcformat = COERCE_EXPLICIT_CALL;
+ funcexpr->argformat = argformat;
funcexpr->args = fargs;
funcexpr->location = location;
***************
*** 807,812 ****
--- 843,849 ----
FuncDetailCode
func_get_detail(List *funcname,
List *fargs,
+ List *argnames,
int nargs,
Oid *argtypes,
bool expand_variadic,
***************
*** 816,828 ****
bool *retset, /* return value */
int *nvargs, /* return value */
Oid **true_typeids, /* return value */
! List **argdefaults) /* optional return value */
{
FuncCandidateList raw_candidates;
FuncCandidateList best_candidate;
/* Get list of possible candidates from namespace search */
! raw_candidates = FuncnameGetCandidates(funcname, nargs,
expand_variadic, expand_defaults);
/*
--- 853,867 ----
bool *retset, /* return value */
int *nvargs, /* return value */
Oid **true_typeids, /* return value */
! List **argdefaults, /* optional return value */
! short int **param_map, /* optional return value */
! int *pronargs) /* optional return value */
{
FuncCandidateList raw_candidates;
FuncCandidateList best_candidate;
/* Get list of possible candidates from namespace search */
! raw_candidates = FuncnameGetCandidates(funcname, nargs, argnames,
expand_variadic, expand_defaults);
/*
***************
*** 976,981 ****
--- 1015,1028 ----
pform = (Form_pg_proc) GETSTRUCT(ftup);
*rettype = pform->prorettype;
*retset = pform->proretset;
+
+ if (param_map)
+ {
+ Assert(pronargs != NULL);
+ *pronargs = best_candidate->nargs;
+ *param_map = best_candidate->param_map;
+ }
+
/* fetch default args if caller wants 'em */
if (argdefaults)
{
***************
*** 1141,1146 ****
--- 1188,1195 ----
/* types don't match? then force coercion using a function call... */
if (actual_arg_types[i] != declared_arg_types[i])
{
+ Assert(lfirst(current_fargs) != NULL);
+
lfirst(current_fargs) = coerce_type(pstate,
lfirst(current_fargs),
actual_arg_types[i],
***************
*** 1357,1363 ****
{
FuncCandidateList clist;
! clist = FuncnameGetCandidates(funcname, nargs, false, false);
while (clist)
{
--- 1406,1412 ----
{
FuncCandidateList clist;
! clist = FuncnameGetCandidates(funcname, nargs, NIL, false, false);
while (clist)
{
*** ./src/backend/utils/adt/regproc.c.orig 2009-03-03 14:56:09.000000000 +0100
--- ./src/backend/utils/adt/regproc.c 2009-03-03 14:57:02.000000000 +0100
***************
*** 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-03-03 14:56:02.000000000 +0100
--- ./src/backend/utils/adt/ruleutils.c 2009-03-04 14:17:33.000000000 +0100
***************
*** 6322,6330 ****
* specified argtypes.
*/
p_result = func_get_detail(list_make1(makeString(proname)),
! NIL, nargs, argtypes, false, true,
&p_funcid, &p_rettype,
! &p_retset, &p_nvargs, &p_true_typeids, NULL);
if ((p_result == FUNCDETAIL_NORMAL ||
p_result == FUNCDETAIL_AGGREGATE ||
p_result == FUNCDETAIL_WINDOWFUNC) &&
--- 6322,6330 ----
* specified argtypes.
*/
p_result = func_get_detail(list_make1(makeString(proname)),
! NIL, NIL, nargs, argtypes, false, true,
&p_funcid, &p_rettype,
! &p_retset, &p_nvargs, &p_true_typeids, NULL, NULL, NULL);
if ((p_result == FUNCDETAIL_NORMAL ||
p_result == FUNCDETAIL_AGGREGATE ||
p_result == FUNCDETAIL_WINDOWFUNC) &&
*** ./src/include/catalog/namespace.h.orig 2009-03-03 14:49:23.000000000 +0100
--- ./src/include/catalog/namespace.h 2009-03-04 09:14:42.000000000 +0100
***************
*** 32,37 ****
--- 32,38 ----
int nargs; /* number of arg types returned */
int nvargs; /* number of args to become variadic array */
int ndargs; /* number of defaulted args */
+ short int *param_map; /* maps external arguments to function arguments */
Oid args[1]; /* arg types --- VARIABLE LENGTH ARRAY */
} *FuncCandidateList; /* VARIABLE LENGTH STRUCT */
***************
*** 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-02-25 04:30:37.000000000 +0100
--- ./src/include/nodes/nodes.h 2009-03-03 13:13:42.000000000 +0100
***************
*** 378,383 ****
--- 378,384 ----
T_XmlSerialize,
T_WithClause,
T_CommonTableExpr,
+ T_ArgExpr,
/*
* TAGS FOR RANDOM OTHER STUFF
*** ./src/include/nodes/parsenodes.h.orig 2009-03-03 13:13:22.000000000 +0100
--- ./src/include/nodes/parsenodes.h 2009-03-03 14:15:03.000000000 +0100
***************
*** 289,294 ****
--- 289,312 ----
} FuncCall;
/*
+ * ArgExpr - an argument of function
+ */
+ typedef struct ArgExpr
+ {
+ NodeTag type;
+ char *name; /* an name of argument (when is specified) */
+ Node *expr; /* the argument */
+ } ArgExpr;
+
+
+ /* notation used for Func call params */
+ typedef enum FuncCallNotation
+ {
+ POSITIONAL_NOTATION,
+ NAMED_NOTATION
+ } FuncCallNotation;
+
+ /*
* A_Star - '*' representing all columns of a table or compound field
*
* This can appear within ColumnRef.fields, A_Indirection.indirection, and
*** ./src/include/nodes/primnodes.h.orig 2009-03-04 14:12:16.000000000 +0100
--- ./src/include/nodes/primnodes.h 2009-03-04 14:13:43.000000000 +0100
***************
*** 299,304 ****
--- 299,310 ----
COERCE_DONTCARE /* special case for planner */
} CoercionForm;
+ typedef enum ArgumentForm
+ {
+ CONTINUOUS_LIST, /* used for positional notation */
+ LEAKY_LIST /* used for named and mixed notation */
+ } ArgumentForm;
+
/*
* FuncExpr - expression node for a function call
*/
***************
*** 309,314 ****
--- 315,321 ----
Oid funcresulttype; /* PG_TYPE OID of result value */
bool funcretset; /* true if function returns set */
CoercionForm funcformat; /* how to display this function call */
+ ArgumentForm argformat; /* what is format of argument list */
List *args; /* arguments to the function */
int location; /* token location, or -1 if unknown */
} FuncExpr;
*** ./src/include/parser/parse_func.h.orig 2009-03-03 14:16:15.000000000 +0100
--- ./src/include/parser/parse_func.h 2009-03-04 11:52:54.000000000 +0100
***************
*** 45,58 ****
extern Node *ParseFuncOrColumn(ParseState *pstate,
List *funcname, List *fargs,
bool agg_star, bool agg_distinct, bool func_variadic,
! WindowDef *over, bool is_column, int location);
! extern FuncDetailCode func_get_detail(List *funcname, List *fargs,
! int nargs, Oid *argtypes,
bool expand_variadic, bool expand_defaults,
Oid *funcid, Oid *rettype,
bool *retset, int *nvargs, Oid **true_typeids,
! List **argdefaults);
extern int func_match_argtypes(int nargs,
Oid *input_typeids,
--- 45,58 ----
extern Node *ParseFuncOrColumn(ParseState *pstate,
List *funcname, List *fargs,
bool agg_star, bool agg_distinct, bool func_variadic,
! WindowDef *over, bool is_column, List *argnames, int location);
! extern FuncDetailCode func_get_detail(List *funcname, List *fargs, List *argnames,
! int nargs, Oid *argtypes,
bool expand_variadic, bool expand_defaults,
Oid *funcid, Oid *rettype,
bool *retset, int *nvargs, Oid **true_typeids,
! List **argdefaults, short int **param_map, int *pronargs);
extern int func_match_argtypes(int nargs,
Oid *input_typeids,
*** ./src/test/regress/expected/polymorphism.out.orig 2009-03-04 18:57:59.000000000 +0100
--- ./src/test/regress/expected/polymorphism.out 2009-03-04 18:57:14.000000000 +0100
***************
*** 1038,1040 ****
--- 1038,1104 ----
drop function dfunc(int, int, int);
drop function dfunc(int, int);
drop function dfunc(text);
+ -- test function with named params and using named or mixed notation
+ -- fail, unnamed param behind named
+ create function dfunc(a int, b int = 1, c int) returns table (a int, b int, c int) as $$
+ select $1, $2, $3;
+ $$ language sql;
+ ERROR: input parameters after one with a default value must also have defaults
+ create function dfunc(a int, b int, c int=0, d int = 0) returns table (a int, b int, c int, d int) as $$
+ select $1, $2, $3, $4;
+ $$ language sql;
+ select (dfunc(10,20,30)).*;
+ a | b | c | d
+ ----+----+----+---
+ 10 | 20 | 30 | 0
+ (1 row)
+
+ select (dfunc(10 as a, 20 as b, 30 as c)).*;
+ a | b | c | d
+ ----+----+----+---
+ 10 | 20 | 30 | 0
+ (1 row)
+
+ select * from dfunc(10 as a, 20 as b);
+ a | b | c | d
+ ----+----+---+---
+ 10 | 20 | 0 | 0
+ (1 row)
+
+ select * from dfunc(10 as b, 20 as a);
+ a | b | c | d
+ ----+----+---+---
+ 20 | 10 | 0 | 0
+ (1 row)
+
+ select * from dfunc(0,0);
+ a | b | c | d
+ ---+---+---+---
+ 0 | 0 | 0 | 0
+ (1 row)
+
+ select * from dfunc(0,0,10 as c);
+ a | b | c | d
+ ---+---+----+---
+ 0 | 0 | 10 | 0
+ (1 row)
+
+ select * from dfunc(0,0,10 as d);
+ a | b | c | d
+ ---+---+---+----
+ 0 | 0 | 0 | 10
+ (1 row)
+
+ select * from dfunc(10 as x, 20 as b, 30 as c); --fail - unknown param
+ ERROR: function dfunc(integer, integer, integer) does not exist
+ LINE 1: select * from dfunc(10 as x, 20 as b, 30 as c);
+ ^
+ HINT: No function matches the given name and argument types. You might need to add explicit type casts.
+ select * from dfunc(10, 20 as b, 30); -- fail using positional notation begind named notation
+ ERROR: expected named expression
+ LINE 1: select * from dfunc(10, 20 as b, 30);
+ ^
+ HINT: You can't put positionals arguments behind the named arguments.
+ select * from dfunc(10,10,20 as a); --fail - a overlaps first positional parameter
+ ERROR: named parameter "a" overlaps 1. positional parameter
+ drop function dfunc(int, int, int, int);
*** ./src/test/regress/sql/polymorphism.sql.orig 2009-03-04 18:48:30.000000000 +0100
--- ./src/test/regress/sql/polymorphism.sql 2009-03-04 18:56:35.000000000 +0100
***************
*** 624,626 ****
--- 624,650 ----
drop function dfunc(int, int, int);
drop function dfunc(int, int);
drop function dfunc(text);
+
+ -- test function with named params and using named or mixed notation
+ -- fail, unnamed param behind named
+ create function dfunc(a int, b int = 1, c int) returns table (a int, b int, c int) as $$
+ select $1, $2, $3;
+ $$ language sql;
+
+ create function dfunc(a int, b int, c int=0, d int = 0) returns table (a int, b int, c int, d int) as $$
+ select $1, $2, $3, $4;
+ $$ language sql;
+
+ select (dfunc(10,20,30)).*;
+ select (dfunc(10 as a, 20 as b, 30 as c)).*;
+ select * from dfunc(10 as a, 20 as b);
+ select * from dfunc(10 as b, 20 as a);
+ select * from dfunc(0,0);
+ select * from dfunc(0,0,10 as c);
+ select * from dfunc(0,0,10 as d);
+
+ select * from dfunc(10 as x, 20 as b, 30 as c); --fail - unknown param
+ select * from dfunc(10, 20 as b, 30); -- fail using positional notation begind named notation
+ select * from dfunc(10,10,20 as a); --fail - a overlaps first positional parameter
+
+ drop function dfunc(int, int, int, int);