diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c index eae888e5011..7a38226c312 100644 --- a/src/backend/parser/parse_coerce.c +++ b/src/backend/parser/parse_coerce.c @@ -752,25 +752,33 @@ coerce_type_typmod(Node *node, Oid targetTypeId, int32 targetTypMod, CoercionPathType pathtype; Oid funcId; - /* - * A negative typmod is assumed to mean that no coercion is wanted. Also, - * skip coercion if already done. - */ - if (targetTypMod < 0 || targetTypMod == exprTypmod(node)) + /* Skip coercion if already done */ + if (targetTypMod == exprTypmod(node)) return node; + /* Suppress display of nested coercion steps */ + if (hideInputCoercion) + hide_coercion_node(node); + pathtype = find_typmod_coercion_function(targetTypeId, &funcId); if (pathtype != COERCION_PATH_NONE) { - /* Suppress display of nested coercion steps */ - if (hideInputCoercion) - hide_coercion_node(node); - node = build_coercion_expression(node, pathtype, funcId, targetTypeId, targetTypMod, ccontext, cformat, location); } + else + { + /* + * We don't need to perform any actual coercion step, but we should + * apply a RelabelType to ensure that the expression exposes the + * intended typmod. + */ + node = applyRelabelType(node, targetTypeId, targetTypMod, + exprCollation(node), + cformat, location, false); + } return node; } diff --git a/src/test/regress/expected/expressions.out b/src/test/regress/expected/expressions.out index 719455b0ebb..4ca89ae5592 100644 --- a/src/test/regress/expected/expressions.out +++ b/src/test/regress/expected/expressions.out @@ -75,3 +75,40 @@ SELECT current_schema; (1 row) RESET search_path; +-- +-- Test parsing of a no-op cast to a type with unspecified typmod +-- +begin; +create table numeric_tbl (f1 numeric(18,3), f2 numeric); +create view numeric_view as + select + f1, f1::numeric(16,4) as f1164, f1::numeric as f1n, + f2, f2::numeric(16,4) as f2164, f2::numeric as f2n + from numeric_tbl; +\d+ numeric_view + View "public.numeric_view" + Column | Type | Collation | Nullable | Default | Storage | Description +--------+---------------+-----------+----------+---------+---------+------------- + f1 | numeric(18,3) | | | | main | + f1164 | numeric(16,4) | | | | main | + f1n | numeric | | | | main | + f2 | numeric | | | | main | + f2164 | numeric(16,4) | | | | main | + f2n | numeric | | | | main | +View definition: + SELECT numeric_tbl.f1, + numeric_tbl.f1::numeric(16,4) AS f1164, + numeric_tbl.f1::numeric AS f1n, + numeric_tbl.f2, + numeric_tbl.f2::numeric(16,4) AS f2164, + numeric_tbl.f2 AS f2n + FROM numeric_tbl; + +explain (verbose, costs off) select * from numeric_view; + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------- + Seq Scan on public.numeric_tbl + Output: numeric_tbl.f1, (numeric_tbl.f1)::numeric(16,4), (numeric_tbl.f1)::numeric, numeric_tbl.f2, (numeric_tbl.f2)::numeric(16,4), numeric_tbl.f2 +(2 rows) + +rollback; diff --git a/src/test/regress/sql/expressions.sql b/src/test/regress/sql/expressions.sql index 3427fdfdd72..0c57531ec1e 100644 --- a/src/test/regress/sql/expressions.sql +++ b/src/test/regress/sql/expressions.sql @@ -34,3 +34,23 @@ SELECT current_schema; SET search_path = 'pg_catalog'; SELECT current_schema; RESET search_path; + + +-- +-- Test parsing of a no-op cast to a type with unspecified typmod +-- +begin; + +create table numeric_tbl (f1 numeric(18,3), f2 numeric); + +create view numeric_view as + select + f1, f1::numeric(16,4) as f1164, f1::numeric as f1n, + f2, f2::numeric(16,4) as f2164, f2::numeric as f2n + from numeric_tbl; + +\d+ numeric_view + +explain (verbose, costs off) select * from numeric_view; + +rollback;