aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/utils/adt/ruleutils.c18
-rw-r--r--src/test/regress/expected/create_view.out28
-rw-r--r--src/test/regress/sql/create_view.sql11
3 files changed, 57 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, ')');
diff --git a/src/test/regress/expected/create_view.out b/src/test/regress/expected/create_view.out
index ae50c946079..81b4e8d42bb 100644
--- a/src/test/regress/expected/create_view.out
+++ b/src/test/regress/expected/create_view.out
@@ -1502,6 +1502,34 @@ explain (costs off) select * from tt18v;
-> Seq Scan on int8_tbl xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_1
(3 rows)
+-- check display of ScalarArrayOp with a sub-select
+select 'foo'::text = any(array['abc','def','foo']::text[]);
+ ?column?
+----------
+ t
+(1 row)
+
+select 'foo'::text = any((select array['abc','def','foo']::text[])); -- fail
+ERROR: operator does not exist: text = text[]
+LINE 1: select 'foo'::text = any((select array['abc','def','foo']::t...
+ ^
+HINT: No operator matches the given name and argument type(s). You might need to add explicit type casts.
+select 'foo'::text = any((select array['abc','def','foo']::text[])::text[]);
+ ?column?
+----------
+ t
+(1 row)
+
+create view tt19v as
+select 'foo'::text = any(array['abc','def','foo']::text[]) c1,
+ 'foo'::text = any((select array['abc','def','foo']::text[])::text[]) c2;
+select pg_get_viewdef('tt19v', true);
+ pg_get_viewdef
+------------------------------------------------------------------------------------------------------------
+ SELECT 'foo'::text = ANY (ARRAY['abc'::text, 'def'::text, 'foo'::text]) AS c1, +
+ 'foo'::text = ANY ((( SELECT ARRAY['abc'::text, 'def'::text, 'foo'::text] AS "array"))::text[]) AS c2;
+(1 row)
+
-- clean up all the random objects we made above
set client_min_messages = warning;
DROP SCHEMA temp_view_test CASCADE;
diff --git a/src/test/regress/sql/create_view.sql b/src/test/regress/sql/create_view.sql
index 58d361df649..8bed5a53b3a 100644
--- a/src/test/regress/sql/create_view.sql
+++ b/src/test/regress/sql/create_view.sql
@@ -496,6 +496,17 @@ create view tt18v as
select pg_get_viewdef('tt18v', true);
explain (costs off) select * from tt18v;
+-- check display of ScalarArrayOp with a sub-select
+
+select 'foo'::text = any(array['abc','def','foo']::text[]);
+select 'foo'::text = any((select array['abc','def','foo']::text[])); -- fail
+select 'foo'::text = any((select array['abc','def','foo']::text[])::text[]);
+
+create view tt19v as
+select 'foo'::text = any(array['abc','def','foo']::text[]) c1,
+ 'foo'::text = any((select array['abc','def','foo']::text[])::text[]) c2;
+select pg_get_viewdef('tt19v', true);
+
-- clean up all the random objects we made above
set client_min_messages = warning;
DROP SCHEMA temp_view_test CASCADE;