1
0
mirror of https://github.com/postgres/postgres.git synced 2025-05-12 16:21:30 +03:00

Fix non-equivalence of VARIADIC and non-VARIADIC function call formats.

For variadic functions (other than VARIADIC ANY), the syntaxes foo(x,y,...)
and foo(VARIADIC ARRAY[x,y,...]) should be considered equivalent, since the
former is converted to the latter at parse time.  They have indeed been
equivalent, in all releases before 9.3.  However, commit 75b39e790 made an
ill-considered decision to record which syntax had been used in FuncExpr
nodes, and then to make equal() test that in checking node equality ---
which caused the syntaxes to not be seen as equivalent by the planner.
This is the underlying cause of bug #9817 from Dmitry Ryabov.

It might seem that a quick fix would be to make equal() disregard
FuncExpr.funcvariadic, but the same commit made that untenable, because
the field actually *is* semantically significant for some VARIADIC ANY
functions.  This patch instead adopts the approach of redefining
funcvariadic (and aggvariadic, in HEAD) as meaning that the last argument
is a variadic array, whether it got that way by parser intervention or was
supplied explicitly by the user.  Therefore the value will always be true
for non-ANY variadic functions, restoring the principle of equivalence.
(However, the planner will continue to consider use of VARIADIC as a
meaningful difference for VARIADIC ANY functions, even though some such
functions might disregard it.)

In HEAD, this change lets us simplify the decompilation logic in
ruleutils.c, since the funcvariadic/aggvariadic flag tells directly whether
to print VARIADIC.  However, in 9.3 we have to continue to cope with
existing stored rules/views that might contain the previous definition.
Fortunately, this just means no change in ruleutils.c, since its existing
behavior effectively ignores funcvariadic for all cases other than VARIADIC
ANY functions.

In HEAD, bump catversion to reflect the fact that FuncExpr.funcvariadic
changed meanings; this is sort of pro forma, since I don't believe any
built-in views are affected.

Unfortunately, this patch doesn't magically fix everything for affected
9.3 users.  After installing 9.3.5, they might need to recreate their
rules/views/indexes containing variadic function calls in order to get
everything consistent with the new definition.  As in the cited bug,
the symptom of a problem would be failure to use a nominally matching
index that has a variadic function call in its definition.  We'll need
to mention this in the 9.3.5 release notes.
This commit is contained in:
Tom Lane 2014-04-03 22:02:27 -04:00
parent 2186533911
commit d359f71ac0
5 changed files with 24 additions and 13 deletions

View File

@ -3154,9 +3154,10 @@ CREATE OR REPLACE FUNCTION retcomposite(IN integer, IN integer,
is zero based. <function>get_call_result_type</> can also be used is zero based. <function>get_call_result_type</> can also be used
as an alternative to <function>get_fn_expr_rettype</>. as an alternative to <function>get_fn_expr_rettype</>.
There is also <function>get_fn_expr_variadic</>, which can be used to There is also <function>get_fn_expr_variadic</>, which can be used to
find out whether the call contained an explicit <literal>VARIADIC</> find out whether variadic arguments have been merged into an array.
keyword. This is primarily useful for <literal>VARIADIC "any"</> This is primarily useful for <literal>VARIADIC "any"</> functions,
functions, as described below. since such merging will always have occurred for variadic functions
taking ordinary array types.
</para> </para>
<para> <para>

View File

@ -374,6 +374,11 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
newa->location = exprLocation((Node *) vargs); newa->location = exprLocation((Node *) vargs);
fargs = lappend(fargs, newa); fargs = lappend(fargs, newa);
/* We could not have had VARIADIC marking before ... */
Assert(!func_variadic);
/* ... but now, it's a VARIADIC call */
func_variadic = true;
} }
/* build the appropriate output structure */ /* build the appropriate output structure */

View File

@ -8604,7 +8604,7 @@ generate_relation_name(Oid relid, List *namespaces)
* *
* If we're dealing with a potentially variadic function (in practice, this * If we're dealing with a potentially variadic function (in practice, this
* means a FuncExpr and not some other way of calling the function), then * means a FuncExpr and not some other way of calling the function), then
* was_variadic must specify whether VARIADIC appeared in the original call, * was_variadic should specify whether variadic arguments have been merged,
* and *use_variadic_p will be set to indicate whether to print VARIADIC in * and *use_variadic_p will be set to indicate whether to print VARIADIC in
* the output. For non-FuncExpr cases, was_variadic should be FALSE and * the output. For non-FuncExpr cases, was_variadic should be FALSE and
* use_variadic_p can be NULL. * use_variadic_p can be NULL.
@ -8639,14 +8639,16 @@ generate_function_name(Oid funcid, int nargs, List *argnames, Oid *argtypes,
* since it affects the lookup rules in func_get_detail(). * since it affects the lookup rules in func_get_detail().
* *
* Currently, we always print VARIADIC if the function is variadic and * Currently, we always print VARIADIC if the function is variadic and
* takes a variadic type other than ANY. (In principle, if VARIADIC * takes a variadic type other than ANY. However, if the function takes
* wasn't originally specified and the array actual argument is * VARIADIC ANY, then the parser didn't fold the arguments together into
* deconstructable, we could print the array elements separately and not * an array, so we must print VARIADIC if and only if it was used
* print VARIADIC, thus more nearly reproducing the original input. For * originally.
* the moment that seems like too much complication for the benefit.) *
* However, if the function takes VARIADIC ANY, then the parser didn't * Note: with the current definition of funcvariadic, we could just set
* fold the arguments together into an array, so we must print VARIADIC if * use_variadic = was_variadic, which indeed is the solution adopted in
* and only if it was used originally. * 9.4. However, in rules/views stored before 9.3.5, funcvariadic will
* reflect the previous definition (was VARIADIC written in the call?).
* So in 9.3 we cannot trust it unless the function is VARIADIC ANY.
*/ */
if (use_variadic_p) if (use_variadic_p)
{ {

View File

@ -2452,6 +2452,8 @@ get_call_expr_arg_stable(Node *expr, int argnum)
* Get the VARIADIC flag from the function invocation * Get the VARIADIC flag from the function invocation
* *
* Returns false (the default assumption) if information is not available * Returns false (the default assumption) if information is not available
*
* Note this is generally only of interest to VARIADIC ANY functions
*/ */
bool bool
get_fn_expr_variadic(FmgrInfo *flinfo) get_fn_expr_variadic(FmgrInfo *flinfo)

View File

@ -346,7 +346,8 @@ typedef struct FuncExpr
Oid funcid; /* PG_PROC OID of the function */ Oid funcid; /* PG_PROC OID of the function */
Oid funcresulttype; /* PG_TYPE OID of result value */ Oid funcresulttype; /* PG_TYPE OID of result value */
bool funcretset; /* true if function returns set */ bool funcretset; /* true if function returns set */
bool funcvariadic; /* true if VARIADIC was used in call */ bool funcvariadic; /* true if variadic arguments have been
* combined into an array last argument */
CoercionForm funcformat; /* how to display this function call */ CoercionForm funcformat; /* how to display this function call */
Oid funccollid; /* OID of collation of result */ Oid funccollid; /* OID of collation of result */
Oid inputcollid; /* OID of collation that function should use */ Oid inputcollid; /* OID of collation that function should use */