diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index e4a81ceda9d3311005d84ce40b8283ef835d7e4a..1ec1db9081b22b1bcd703f0d323532912c1f599f 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -5214,6 +5214,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 6cf0e672c8e3686a4473f6add644a4ca880b72ea..df6b03025f6258fe481bdff606265681293b59a5 100644 --- a/src/test/regress/expected/create_view.out +++ b/src/test/regress/expected/create_view.out @@ -347,6 +347,34 @@ select * from int8_tbl i where i.* in (values(i.*::int8_tbl)); 4567890123456789 | -4567890123456789 (5 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 f13c9af2e891304e779691aca59e67080be2549b..57c5197633870f1f27cedcca86c028c55f746494 100644 --- a/src/test/regress/sql/create_view.sql +++ b/src/test/regress/sql/create_view.sql @@ -237,6 +237,17 @@ select * from tt17v; select pg_get_viewdef('tt17v', true); select * from int8_tbl i where i.* in (values(i.*::int8_tbl)); +-- 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;