aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/adt/ruleutils.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2014-04-03 22:02:24 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2014-04-03 22:02:24 -0400
commitc7b353959931ae8e95177fe0a138b8119db9b802 (patch)
treed3884341944945557e1bda8e6494c5843b827f52 /src/backend/utils/adt/ruleutils.c
parent741364bf5caeeae79b83bbdba778805d286622ba (diff)
downloadpostgresql-c7b353959931ae8e95177fe0a138b8119db9b802.tar.gz
postgresql-c7b353959931ae8e95177fe0a138b8119db9b802.zip
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.
Diffstat (limited to 'src/backend/utils/adt/ruleutils.c')
-rw-r--r--src/backend/utils/adt/ruleutils.c41
1 files changed, 18 insertions, 23 deletions
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 566b4c910b3..b1bac866aa1 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -401,7 +401,7 @@ static char *get_relation_name(Oid relid);
static char *generate_relation_name(Oid relid, List *namespaces);
static char *generate_function_name(Oid funcid, int nargs,
List *argnames, Oid *argtypes,
- bool was_variadic, bool *use_variadic_p);
+ bool has_variadic, bool *use_variadic_p);
static char *generate_operator_name(Oid operid, Oid arg1, Oid arg2);
static text *string_to_text(char *str);
static char *flatten_reloptions(Oid relid);
@@ -8849,16 +8849,16 @@ generate_relation_name(Oid relid, List *namespaces)
*
* If we're dealing with a potentially variadic function (in practice, this
* means a FuncExpr or Aggref, not some other way of calling a function), then
- * was_variadic must specify whether VARIADIC appeared in the original call,
+ * has_variadic must specify whether variadic arguments have been merged,
* 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, has_variadic should be FALSE and
* use_variadic_p can be NULL.
*
* The result includes all necessary quoting and schema-prefixing.
*/
static char *
generate_function_name(Oid funcid, int nargs, List *argnames, Oid *argtypes,
- bool was_variadic, bool *use_variadic_p)
+ bool has_variadic, bool *use_variadic_p)
{
char *result;
HeapTuple proctup;
@@ -8884,32 +8884,27 @@ generate_function_name(Oid funcid, int nargs, List *argnames, Oid *argtypes,
* Determine whether VARIADIC should be printed. We must do this first
* since it affects the lookup rules in func_get_detail().
*
- * Currently, we always print VARIADIC if the function is variadic and
- * takes a variadic type other than ANY. (In principle, if VARIADIC
- * wasn't originally specified and the array actual argument is
- * deconstructable, we could print the array elements separately and not
- * print VARIADIC, thus more nearly reproducing the original input. For
- * the moment that seems like too much complication for the benefit.)
- * However, if the function takes VARIADIC ANY, then the parser didn't
- * fold the arguments together into an array, so we must print VARIADIC if
- * and only if it was used originally.
+ * Currently, we always print VARIADIC if the function has a merged
+ * variadic-array argument. Note that this is always the case for
+ * functions taking a VARIADIC argument type other than VARIADIC ANY.
+ *
+ * In principle, if VARIADIC wasn't originally specified and the array
+ * actual argument is deconstructable, we could print the array elements
+ * separately and not print VARIADIC, thus more nearly reproducing the
+ * original input. For the moment that seems like too much complication
+ * for the benefit, and anyway we do not know whether VARIADIC was
+ * originally specified if it's a non-ANY type.
*/
if (use_variadic_p)
{
- if (OidIsValid(procform->provariadic))
- {
- if (procform->provariadic != ANYOID)
- use_variadic = true;
- else
- use_variadic = was_variadic;
- }
- else
- use_variadic = false;
+ /* Parser should not have set funcvariadic unless fn is variadic */
+ Assert(!has_variadic || OidIsValid(procform->provariadic));
+ use_variadic = has_variadic;
*use_variadic_p = use_variadic;
}
else
{
- Assert(!was_variadic);
+ Assert(!has_variadic);
use_variadic = false;
}