*** ./doc/src/sgml/xfunc.sgml.orig 2009-07-25 13:03:02.748970806 +0200
--- ./doc/src/sgml/xfunc.sgml 2009-07-25 13:09:39.886973125 +0200
***************
*** 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-07-25 13:03:02.750971910 +0200
--- ./src/backend/catalog/namespace.c 2009-07-25 18:57:02.943971432 +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"
***************
*** 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,724 ----
* 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 && p_argmodes[i] != FUNC_PARAM_VARIADIC))
+ 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))
{
--- 759,812 ----
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 ****
--- 846,852 ----
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?
--- 860,873 ----
}
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)
{
--- 1064,1070 ----
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.
*
--- 1085,1091 ----
/*
! * OpernameGetOpri
* Given a possibly-qualified operator name and exact input datatypes,
* look up the operator. Returns InvalidOid if not found.
*
***************
*** 1204,1209 ****
--- 1336,1342 ----
newResult->ndargs = 0;
newResult->args[0] = operform->oprleft;
newResult->args[1] = operform->oprright;
+ newResult->param_map = NULL;
newResult->next = resultList;
resultList = newResult;
}
*** ./src/backend/catalog/pg_aggregate.c.orig 2009-07-25 13:03:02.752971058 +0200
--- ./src/backend/catalog/pg_aggregate.c 2009-07-25 13:09:39.893974054 +0200
***************
*** 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-07-20 04:42:27.000000000 +0200
--- ./src/backend/nodes/copyfuncs.c 2009-07-25 13:09:39.895973201 +0200
***************
*** 1013,1018 ****
--- 1013,1019 ----
COPY_SCALAR_FIELD(funcresulttype);
COPY_SCALAR_FIELD(funcretset);
COPY_SCALAR_FIELD(funcformat);
+ COPY_SCALAR_FIELD(argformat);
COPY_NODE_FIELD(args);
COPY_LOCATION_FIELD(location);
***************
*** 1913,1918 ****
--- 1914,1930 ----
return newnode;
}
+ static ArgExpr *
+ _copyArgExpr(ArgExpr *from)
+ {
+ ArgExpr *newnode = makeNode(ArgExpr);
+
+ COPY_STRING_FIELD(name);
+ COPY_NODE_FIELD(expr);
+
+ return newnode;
+ }
+
static A_Star *
_copyAStar(A_Star *from)
{
***************
*** 4013,4018 ****
--- 4025,4033 ----
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-07-25 13:03:02.755971457 +0200
--- ./src/backend/nodes/equalfuncs.c 2009-07-25 13:09:39.897971232 +0200
***************
*** 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-07-25 13:03:02.757971165 +0200
--- ./src/backend/nodes/makefuncs.c 2009-07-25 13:09:39.898970527 +0200
***************
*** 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-07-25 13:03:02.769971085 +0200
--- ./src/backend/nodes/outfuncs.c 2009-07-25 13:09:39.906976896 +0200
***************
*** 871,876 ****
--- 871,877 ----
WRITE_OID_FIELD(funcresulttype);
WRITE_BOOL_FIELD(funcretset);
WRITE_ENUM_FIELD(funcformat, CoercionForm);
+ WRITE_ENUM_FIELD(argformat, ArgumentForm);
WRITE_NODE_FIELD(args);
WRITE_LOCATION_FIELD(location);
}
***************
*** 1795,1800 ****
--- 1796,1810 ----
}
static void
+ _outArgExpr(StringInfo str, ArgExpr *node)
+ {
+ WRITE_NODE_TYPE("ARGEXPR");
+
+ WRITE_STRING_FIELD(name);
+ WRITE_NODE_FIELD(expr);
+ }
+
+ static void
_outDefElem(StringInfo str, DefElem *node)
{
WRITE_NODE_TYPE("DEFELEM");
***************
*** 2765,2770 ****
--- 2775,2783 ----
case T_FuncCall:
_outFuncCall(str, obj);
break;
+ case T_ArgExpr:
+ _outArgExpr(str, obj);
+ break;
case T_DefElem:
_outDefElem(str, obj);
break;
*** ./src/backend/nodes/readfuncs.c.orig 2009-07-25 13:03:02.770970938 +0200
--- ./src/backend/nodes/readfuncs.c 2009-07-25 13:09:39.907971441 +0200
***************
*** 519,524 ****
--- 519,525 ----
READ_OID_FIELD(funcresulttype);
READ_BOOL_FIELD(funcretset);
READ_ENUM_FIELD(funcformat, CoercionForm);
+ READ_ENUM_FIELD(argformat, ArgumentForm);
READ_NODE_FIELD(args);
READ_LOCATION_FIELD(location);
*** ./src/backend/optimizer/util/clauses.c.orig 2009-07-20 02:24:30.000000000 +0200
--- ./src/backend/optimizer/util/clauses.c 2009-07-25 13:09:39.912969870 +0200
***************
*** 95,105 ****
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,
--- 95,107 ----
static Expr *simplify_boolean_equality(Oid opno, List *args);
static Expr *simplify_function(Oid funcid,
Oid result_type, int32 result_typmod, List **args,
! bool leaky_list, bool allow_inline,
eval_const_expressions_context *context);
! static List *add_function_defaults(List *args,
! bool leaky_list,
! Oid result_type,
! HeapTuple func_tuple,
! eval_const_expressions_context *context);
static Expr *evaluate_function(Oid funcid,
Oid result_type, int32 result_typmod, List *args,
HeapTuple func_tuple,
***************
*** 2133,2139 ****
*/
simple = simplify_function(expr->funcid,
expr->funcresulttype, exprTypmod(node),
! &args,
true, context);
if (simple) /* successfully simplified it */
return (Node *) simple;
--- 2135,2141 ----
*/
simple = simplify_function(expr->funcid,
expr->funcresulttype, exprTypmod(node),
! &args, expr->argformat == LEAKY_LIST,
true, context);
if (simple) /* successfully simplified it */
return (Node *) simple;
***************
*** 2148,2153 ****
--- 2150,2156 ----
newexpr->funcresulttype = expr->funcresulttype;
newexpr->funcretset = expr->funcretset;
newexpr->funcformat = expr->funcformat;
+ newexpr->argformat = expr->argformat;
newexpr->args = args;
newexpr->location = expr->location;
return (Node *) newexpr;
***************
*** 2180,2186 ****
*/
simple = simplify_function(expr->opfuncid,
expr->opresulttype, -1,
! &args,
true, context);
if (simple) /* successfully simplified it */
return (Node *) simple;
--- 2183,2189 ----
*/
simple = simplify_function(expr->opfuncid,
expr->opresulttype, -1,
! &args, false,
true, context);
if (simple) /* successfully simplified it */
return (Node *) simple;
***************
*** 2273,2279 ****
*/
simple = simplify_function(expr->opfuncid,
expr->opresulttype, -1,
! &args,
false, context);
if (simple) /* successfully simplified it */
{
--- 2276,2282 ----
*/
simple = simplify_function(expr->opfuncid,
expr->opresulttype, -1,
! &args, false,
false, context);
if (simple) /* successfully simplified it */
{
***************
*** 2465,2471 ****
simple = simplify_function(outfunc,
CSTRINGOID, -1,
! &args,
true, context);
if (simple) /* successfully simplified output fn */
{
--- 2468,2474 ----
simple = simplify_function(outfunc,
CSTRINGOID, -1,
! &args, false,
true, context);
if (simple) /* successfully simplified output fn */
{
***************
*** 2483,2489 ****
simple = simplify_function(infunc,
expr->resulttype, -1,
! &args,
true, context);
if (simple) /* successfully simplified input fn */
return (Node *) simple;
--- 2486,2492 ----
simple = simplify_function(infunc,
expr->resulttype, -1,
! &args, false,
true, context);
if (simple) /* successfully simplified input fn */
return (Node *) simple;
***************
*** 3250,3255 ****
--- 3253,3259 ----
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)
{
***************
*** 3271,3278 ****
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);
--- 3275,3282 ----
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);
***************
*** 3295,3301 ****
* 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);
--- 3299,3305 ----
* 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);
***************
*** 3321,3334 ****
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);
/*
--- 3325,3365 ----
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);
/*
***************
*** 3467,3472 ****
--- 3498,3504 ----
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-07-25 02:07:11.000000000 +0200
--- ./src/backend/parser/gram.y 2009-07-25 18:04:25.319969328 +0200
***************
*** 419,424 ****
--- 419,427 ----
%type opt_existing_window_name
%type opt_frame_clause frame_extent frame_bound
+ %type arg_expr_list
+ %type arg_expr
+
/*
* Non-keyword token types. These are hard-wired into the "flex" lexer.
***************
*** 8820,8826 ****
n->location = @1;
$$ = (Node *)n;
}
! | func_name '(' expr_list ')' over_clause
{
FuncCall *n = makeNode(FuncCall);
n->funcname = $1;
--- 8823,8829 ----
n->location = @1;
$$ = (Node *)n;
}
! | func_name '(' arg_expr_list ')' over_clause
{
FuncCall *n = makeNode(FuncCall);
n->funcname = $1;
***************
*** 8832,8838 ****
n->location = @1;
$$ = (Node *)n;
}
! | func_name '(' VARIADIC a_expr ')' over_clause
{
FuncCall *n = makeNode(FuncCall);
n->funcname = $1;
--- 8835,8841 ----
n->location = @1;
$$ = (Node *)n;
}
! | func_name '(' VARIADIC arg_expr ')' over_clause
{
FuncCall *n = makeNode(FuncCall);
n->funcname = $1;
***************
*** 8844,8850 ****
n->location = @1;
$$ = (Node *)n;
}
! | func_name '(' expr_list ',' VARIADIC a_expr ')' over_clause
{
FuncCall *n = makeNode(FuncCall);
n->funcname = $1;
--- 8847,8853 ----
n->location = @1;
$$ = (Node *)n;
}
! | func_name '(' arg_expr_list ',' VARIADIC arg_expr ')' over_clause
{
FuncCall *n = makeNode(FuncCall);
n->funcname = $1;
***************
*** 8856,8862 ****
n->location = @1;
$$ = (Node *)n;
}
! | func_name '(' ALL expr_list ')' over_clause
{
FuncCall *n = makeNode(FuncCall);
n->funcname = $1;
--- 8859,8865 ----
n->location = @1;
$$ = (Node *)n;
}
! | func_name '(' ALL arg_expr_list ')' over_clause
{
FuncCall *n = makeNode(FuncCall);
n->funcname = $1;
***************
*** 8872,8878 ****
n->location = @1;
$$ = (Node *)n;
}
! | func_name '(' DISTINCT expr_list ')' over_clause
{
FuncCall *n = makeNode(FuncCall);
n->funcname = $1;
--- 8875,8881 ----
n->location = @1;
$$ = (Node *)n;
}
! | func_name '(' DISTINCT arg_expr_list ')' over_clause
{
FuncCall *n = makeNode(FuncCall);
n->funcname = $1;
***************
*** 9595,9600 ****
--- 9598,9628 ----
}
;
+ /* 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); }
;
***************
*** 9994,10000 ****
;
! name: ColId { $$ = $1; };
database_name:
ColId { $$ = $1; };
--- 10022,10028 ----
;
! name: ColId { $$ = $1; };
database_name:
ColId { $$ = $1; };
***************
*** 10027,10033 ****
/*
! * Constants
*/
AexprConst: Iconst
{
--- 10055,10061 ----
/*
! * Constants ToDo - PStehule
*/
AexprConst: Iconst
{
***************
*** 10061,10070 ****
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);
--- 10089,10106 ----
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-07-25 13:03:02.779970738 +0200
--- ./src/backend/parser/parse_expr.c 2009-07-25 13:09:39.921974417 +0200
***************
*** 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-07-25 13:03:02.781970166 +0200
--- ./src/backend/parser/parse_func.c 2009-07-25 18:58:26.021973607 +0200
***************
*** 59,65 ****
Node *
ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
bool agg_star, bool agg_distinct, bool func_variadic,
! WindowDef *over, bool is_column, int location)
{
Oid rettype;
Oid funcid;
--- 59,65 ----
Node *
ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
bool agg_star, bool agg_distinct, bool func_variadic,
! WindowDef *over, bool is_column, List *argnames, int location)
{
Oid rettype;
Oid funcid;
***************
*** 75,80 ****
--- 75,83 ----
bool retset;
int nvargs;
FuncDetailCode fdresult;
+ short int *param_map;
+ int pronargs;
+ ArgumentForm argformat = CONTINUOUS_LIST;
/*
* Most of the rest of the parser just assumes that functions do not have
***************
*** 130,136 ****
* wasn't any aggregate or variadic decoration.
*/
if (nargs == 1 && !agg_star && !agg_distinct && over == NULL &&
! !func_variadic && list_length(funcname) == 1)
{
Oid argtype = actual_arg_types[0];
--- 133,139 ----
* wasn't any aggregate or variadic decoration.
*/
if (nargs == 1 && !agg_star && !agg_distinct && over == NULL &&
! !func_variadic && list_length(funcname) == 1 && argnames == NIL)
{
Oid argtype = actual_arg_types[0];
***************
*** 161,170 ****
* replaced by a suitable number of copies of its element type. We'll fix
* it up below. We may also have to deal with default arguments.
*/
! fdresult = func_get_detail(funcname, fargs, nargs, actual_arg_types,
!func_variadic, true,
&funcid, &rettype, &retset, &nvargs,
! &declared_arg_types, &argdefaults);
if (fdresult == FUNCDETAIL_COERCION)
{
/*
--- 164,173 ----
* replaced by a suitable number of copies of its element type. We'll fix
* it up below. We may also have to deal with default arguments.
*/
! fdresult = func_get_detail(funcname, fargs, argnames, nargs, actual_arg_types,
!func_variadic, true,
&funcid, &rettype, &retset, &nvargs,
! &declared_arg_types, &argdefaults, ¶m_map, &pronargs);
if (fdresult == FUNCDETAIL_COERCION)
{
/*
***************
*** 241,269 ****
parser_errposition(pstate, location)));
}
! /*
! * If there are default arguments, we have to include their types in
! * actual_arg_types for the purpose of checking generic type consistency.
! * However, we do NOT put them into the generated parse node, because
! * their actual values might change before the query gets run. The
! * planner has to insert the up-to-date values at plan time.
! */
! nargsplusdefs = nargs;
! foreach(l, argdefaults)
{
! Node *expr = (Node *) lfirst(l);
! /* probably shouldn't happen ... */
! if (nargsplusdefs >= FUNC_MAX_ARGS)
! ereport(ERROR,
! (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
! errmsg_plural("cannot pass more than %d argument to a function",
! "cannot pass more than %d arguments to a function",
! FUNC_MAX_ARGS,
! FUNC_MAX_ARGS),
! parser_errposition(pstate, location)));
! actual_arg_types[nargsplusdefs++] = exprType(expr);
}
/*
--- 244,305 ----
parser_errposition(pstate, location)));
}
!
! if (param_map != NULL)
{
! List *rfargs = NIL; /* reordered list of function arguments */
! int i;
! for (i = 0; i < pronargs; i++)
! {
! Node *expr = NULL;
! if (param_map[i] < nargs)
! {
! expr = (Node *) list_nth(fargs, param_map[i]);
! rfargs = lappend(rfargs, expr);
! /* when any arg goes out of narg */
! if (i >= nargs)
! argformat = LEAKY_LIST;
! }
! else
! {
! expr = (Node *) list_nth(argdefaults, param_map[i] - nargs);
! rfargs = lappend(rfargs, NULL);
! }
! actual_arg_types[i] = exprType(expr);
! }
!
! fargs = (argformat == LEAKY_LIST) ? rfargs : list_truncate(rfargs, nargs);
! nargsplusdefs = pronargs;
! }
! else
! {
! /*
! * If there are default arguments, we have to include their types in
! * actual_arg_types for the purpose of checking generic type consistency.
! * However, we do NOT put them into the generated parse node, because
! * their actual values might change before the query gets run. The
! * planner has to insert the up-to-date values at plan time.
! */
!
! nargsplusdefs = nargs;
! foreach(l, argdefaults)
! {
! Node *expr = (Node *) lfirst(l);
!
! /* probably shouldn't happen ... */
! if (nargsplusdefs >= FUNC_MAX_ARGS)
! ereport(ERROR,
! (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
! errmsg_plural("cannot pass more than %d argument to a function",
! "cannot pass more than %d arguments to a function",
! FUNC_MAX_ARGS,
! FUNC_MAX_ARGS),
! parser_errposition(pstate, location)));
!
! actual_arg_types[nargsplusdefs++] = exprType(expr);
! }
}
/*
***************
*** 319,324 ****
--- 355,361 ----
funcexpr->funcresulttype = rettype;
funcexpr->funcretset = retset;
funcexpr->funcformat = COERCE_EXPLICIT_CALL;
+ funcexpr->argformat = argformat;
funcexpr->args = fargs;
funcexpr->location = location;
***************
*** 446,457 ****
current_candidate = next_candidate)
{
next_candidate = current_candidate->next;
! if (can_coerce_type(nargs, input_typeids, current_candidate->args,
! COERCION_IMPLICIT))
{
! current_candidate->next = *candidates;
! *candidates = current_candidate;
! ncandidates++;
}
}
--- 483,528 ----
current_candidate = next_candidate)
{
next_candidate = current_candidate->next;
!
! /*
! * When named params are used, we have to remap argtypes too.
! */
! if (current_candidate->param_map == NULL)
{
! if (can_coerce_type(nargs, input_typeids, current_candidate->args,
! COERCION_IMPLICIT))
! {
! current_candidate->next = *candidates;
! *candidates = current_candidate;
! ncandidates++;
! }
! }
! else
! {
! int i;
! Oid args[FUNC_MAX_ARGS];
! short int *param_map = current_candidate->param_map;
!
! /*
! * When any named parameter is used, then candidate param_map and args
! * has funcdef items always. Using an default parameter doesn't change
! * this fact. When dafaults are used, then input_typeids is truncated
! * to number of calling parameters.
! */
! Assert(nargs < FUNC_MAX_ARGS);
! Assert(nargs <= current_candidate->nargs);
!
! /* adjust position for all defined params */
! for (i = 0; i < current_candidate->nargs; i++)
! args[param_map[i]] = current_candidate->args[i];
!
! /* but check ony calling params */
! if (can_coerce_type(nargs, input_typeids, args, COERCION_IMPLICIT))
! {
! current_candidate->next = *candidates;
! *candidates = current_candidate;
! ncandidates++;
! }
}
}
***************
*** 809,814 ****
--- 880,886 ----
FuncDetailCode
func_get_detail(List *funcname,
List *fargs,
+ List *argnames,
int nargs,
Oid *argtypes,
bool expand_variadic,
***************
*** 817,824 ****
Oid *rettype, /* return value */
bool *retset, /* return value */
int *nvargs, /* return value */
! Oid **true_typeids, /* return value */
! List **argdefaults) /* optional return value */
{
FuncCandidateList raw_candidates;
FuncCandidateList best_candidate;
--- 889,898 ----
Oid *rettype, /* return value */
bool *retset, /* return value */
int *nvargs, /* return value */
! Oid **true_typeids, /* return value */
! List **argdefaults, /* optional return value */
! short int **param_map, /* optional return value */
! int *pronargs) /* optional return value */
{
FuncCandidateList raw_candidates;
FuncCandidateList best_candidate;
***************
*** 833,839 ****
*argdefaults = NIL;
/* Get list of possible candidates from namespace search */
! raw_candidates = FuncnameGetCandidates(funcname, nargs,
expand_variadic, expand_defaults);
/*
--- 907,913 ----
*argdefaults = NIL;
/* Get list of possible candidates from namespace search */
! raw_candidates = FuncnameGetCandidates(funcname, nargs, argnames,
expand_variadic, expand_defaults);
/*
***************
*** 987,992 ****
--- 1061,1074 ----
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)
{
***************
*** 1060,1065 ****
--- 1142,1149 ----
/* 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],
***************
*** 1276,1282 ****
{
FuncCandidateList clist;
! clist = FuncnameGetCandidates(funcname, nargs, false, false);
while (clist)
{
--- 1360,1366 ----
{
FuncCandidateList clist;
! clist = FuncnameGetCandidates(funcname, nargs, NIL, false, false);
while (clist)
{
*** ./src/backend/utils/adt/regproc.c.orig 2009-07-25 13:03:02.783970712 +0200
--- ./src/backend/utils/adt/regproc.c 2009-07-25 13:09:39.924970624 +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-07-24 23:08:42.000000000 +0200
--- ./src/backend/utils/adt/ruleutils.c 2009-07-25 13:09:39.928970875 +0200
***************
*** 6361,6369 ****
* 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) &&
--- 6361,6369 ----
* 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-07-25 13:03:02.788970818 +0200
--- ./src/include/catalog/namespace.h 2009-07-25 13:09:39.936979480 +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 */
+ short int *param_map; /* maps external arguments to function arguments */
Oid args[1]; /* arg types --- VARIABLE LENGTH ARRAY */
} *FuncCandidateList; /* VARIABLE LENGTH STRUCT */
***************
*** 55,62 ****
extern bool TypeIsVisible(Oid typid);
extern FuncCandidateList FuncnameGetCandidates(List *names, int nargs,
! bool expand_variadic,
! bool expand_defaults);
extern bool FunctionIsVisible(Oid funcid);
extern Oid OpernameGetOprid(List *names, Oid oprleft, Oid oprright);
--- 56,64 ----
extern bool TypeIsVisible(Oid typid);
extern FuncCandidateList FuncnameGetCandidates(List *names, int nargs,
! List *argnames,
! bool expand_variadic,
! bool expand_defaults);
extern bool FunctionIsVisible(Oid funcid);
extern Oid OpernameGetOprid(List *names, Oid oprleft, Oid oprright);
*** ./src/include/nodes/nodes.h.orig 2009-07-25 13:03:02.790970805 +0200
--- ./src/include/nodes/nodes.h 2009-07-25 13:09:39.937971790 +0200
***************
*** 376,381 ****
--- 376,382 ----
T_XmlSerialize,
T_WithClause,
T_CommonTableExpr,
+ T_ArgExpr,
/*
* TAGS FOR RANDOM OTHER STUFF
*** ./src/include/nodes/parsenodes.h.orig 2009-07-25 13:03:02.792970791 +0200
--- ./src/include/nodes/parsenodes.h 2009-07-25 13:09:39.938971644 +0200
***************
*** 282,287 ****
--- 282,305 ----
} FuncCall;
/*
+ * ArgExpr - an argument of function
+ */
+ typedef struct ArgExpr
+ {
+ NodeTag type;
+ char *name; /* an name of argument (when is specified) */
+ Node *expr; /* the argument */
+ } ArgExpr;
+
+
+ /* notation used for Func call params */
+ typedef enum FuncCallNotation
+ {
+ POSITIONAL_NOTATION,
+ NAMED_NOTATION
+ } FuncCallNotation;
+
+ /*
* A_Star - '*' representing all columns of a table or compound field
*
* This can appear within ColumnRef.fields, A_Indirection.indirection, and
*** ./src/include/nodes/primnodes.h.orig 2009-07-25 13:03:02.793972041 +0200
--- ./src/include/nodes/primnodes.h 2009-07-25 13:09:39.940972188 +0200
***************
*** 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-07-25 13:03:02.795971470 +0200
--- ./src/include/parser/parse_func.h 2009-07-25 13:09:39.940972188 +0200
***************
*** 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-07-25 13:03:02.796971602 +0200
--- ./src/test/regress/expected/polymorphism.out 2009-07-25 19:44:10.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,1287 ----
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);
+ -- 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 named and default params
+ create function dfunc(a varchar = 'def a', b date = 'infinity', c numeric = -1, variadic d int[] = '{}')
+ returns table (a varchar, b date, c numeric, d int[]) as $$
+ select $1, $2, $3, $4;
+ $$ language sql;
+ select (dfunc()).*;
+ a | b | c | d
+ -------+----------+----+----
+ def a | infinity | -1 | {}
+ (1 row)
+
+ select * from dfunc();
+ a | b | c | d
+ -------+----------+----+----
+ def a | infinity | -1 | {}
+ (1 row)
+
+ -- variadic parameter should be used only without using named params,
+ -- because cannot be named and have to be last => there cannot be any
+ -- named params before.
+ select * from dfunc('Hello World', to_date('2009-07-25','YYYY-MM-DD'), 100, 1,2,3,4,5);
+ a | b | c | d
+ -------------+------------+-----+-------------
+ Hello World | 07-25-2009 | 100 | {1,2,3,4,5}
+ (1 row)
+
+ -- defaults, variadic default and named together
+ select * from dfunc('Hello World');
+ a | b | c | d
+ -------------+----------+----+----
+ Hello World | infinity | -1 | {}
+ (1 row)
+
+ select * from dfunc('Hello World', to_date('2009-07-25','YYYY-MM-DD'));
+ a | b | c | d
+ -------------+------------+----+----
+ Hello World | 07-25-2009 | -1 | {}
+ (1 row)
+
+ select * from dfunc('Hello World', to_date('2009-07-25','YYYY-MM-DD'), 100 as c);
+ a | b | c | d
+ -------------+------------+-----+----
+ Hello World | 07-25-2009 | 100 | {}
+ (1 row)
+
+ select * from dfunc('Hello World' as a, 100 as c);
+ a | b | c | d
+ -------------+----------+-----+----
+ Hello World | infinity | 100 | {}
+ (1 row)
+
+ select * from dfunc(100 as c);
+ a | b | c | d
+ -------+----------+-----+----
+ def a | infinity | 100 | {}
+ (1 row)
+
+ select * from dfunc(to_date('2009-07-25','YYYY-MM-DD') as b);
+ a | b | c | d
+ -------+------------+----+----
+ def a | 07-25-2009 | -1 | {}
+ (1 row)
+
+ select * from dfunc(100 as c, to_date('2009-07-25','YYYY-MM-DD') as b);
+ a | b | c | d
+ -------+------------+-----+----
+ def a | 07-25-2009 | 100 | {}
+ (1 row)
+
+ select * from dfunc(to_date('2009-07-25','YYYY-MM-DD') as b, 100 as c);
+ a | b | c | d
+ -------+------------+-----+----
+ def a | 07-25-2009 | 100 | {}
+ (1 row)
+
+ select * from dfunc('Hello World', variadic array[1,2,3] as d);
+ a | b | c | d
+ -------------+----------+----+---------
+ Hello World | infinity | -1 | {1,2,3}
+ (1 row)
+
+ select * from dfunc(variadic array[1,2,3] as d);
+ a | b | c | d
+ -------+----------+----+---------
+ def a | infinity | -1 | {1,2,3}
+ (1 row)
+
+ drop function dfunc(varchar, date, numeric, int[]);
+ -- 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);
*** ./src/test/regress/sql/polymorphism.sql.orig 2009-07-25 13:03:02.798971310 +0200
--- ./src/test/regress/sql/polymorphism.sql 2009-07-25 19:43:18.014972494 +0200
***************
*** 624,626 ****
--- 624,712 ----
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 named and default params
+ create function dfunc(a varchar = 'def a', b date = 'infinity', c numeric = -1, variadic d int[] = '{}')
+ returns table (a varchar, b date, c numeric, d int[]) as $$
+ select $1, $2, $3, $4;
+ $$ language sql;
+
+ select (dfunc()).*;
+ select * from dfunc();
+
+ -- variadic parameter should be used only without using named params,
+ -- because cannot be named and have to be last => there cannot be any
+ -- named params before.
+ select * from dfunc('Hello World', to_date('2009-07-25','YYYY-MM-DD'), 100, 1,2,3,4,5);
+
+ -- defaults, variadic default and named together
+ select * from dfunc('Hello World');
+ select * from dfunc('Hello World', to_date('2009-07-25','YYYY-MM-DD'));
+ select * from dfunc('Hello World', to_date('2009-07-25','YYYY-MM-DD'), 100 as c);
+
+ select * from dfunc('Hello World' as a, 100 as c);
+ select * from dfunc(100 as c);
+ select * from dfunc(to_date('2009-07-25','YYYY-MM-DD') as b);
+ select * from dfunc(100 as c, to_date('2009-07-25','YYYY-MM-DD') as b);
+ select * from dfunc(to_date('2009-07-25','YYYY-MM-DD') as b, 100 as c);
+ select * from dfunc('Hello World', variadic array[1,2,3] as d);
+ select * from dfunc(variadic array[1,2,3] as d);
+
+ drop function dfunc(varchar, date, numeric, int[]);
+
+ -- 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);
+
+