aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/adt/ruleutils.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/utils/adt/ruleutils.c')
-rw-r--r--src/backend/utils/adt/ruleutils.c18
1 files changed, 18 insertions, 0 deletions
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 690df14af22..09053d1041d 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -7203,6 +7203,24 @@ get_rule_expr(Node *node, deparse_context *context,
get_base_element_type(exprType(arg2))),
expr->useOr ? "ANY" : "ALL");
get_rule_expr_paren(arg2, context, true, node);
+
+ /*
+ * There's inherent ambiguity in "x op ANY/ALL (y)" when y is
+ * a bare sub-SELECT. Since we're here, the sub-SELECT must
+ * be meant as a scalar sub-SELECT yielding an array value to
+ * be used in ScalarArrayOpExpr; but the grammar will
+ * preferentially interpret such a construct as an ANY/ALL
+ * SubLink. To prevent misparsing the output that way, insert
+ * a dummy coercion (which will be stripped by parse analysis,
+ * so no inefficiency is added in dump and reload). This is
+ * indeed most likely what the user wrote to get the construct
+ * accepted in the first place.
+ */
+ if (IsA(arg2, SubLink) &&
+ ((SubLink *) arg2)->subLinkType == EXPR_SUBLINK)
+ appendStringInfo(buf, "::%s",
+ format_type_with_typemod(exprType(arg2),
+ exprTypmod(arg2)));
appendStringInfoChar(buf, ')');
if (!PRETTY_PAREN(context))
appendStringInfoChar(buf, ')');