mirror of
https://github.com/postgres/postgres.git
synced 2025-05-01 01:04:50 +03:00
Don't elide casting to typmod -1.
Casting a value that's already of a type with a specific typmod to an unspecified typmod doesn't do anything so far as run-time behavior is concerned. However, it really ought to change the exposed type of the expression to match. Up to now, coerce_type_typmod hasn't bothered with that, which creates gotchas in contexts such as recursive unions. If for example one side of the union is numeric(18,3), but it needs to be plain numeric to match the other side, there's no direct way to express that. This is easy enough to fix, by inserting a RelabelType to update the exposed type of the expression. However, it's a bit nervous-making to change this behavior, because it's stood for a really long time. But no complaints have emerged about 14beta3, so go ahead and back-patch. Back-patch of 5c056b0c2 into previous supported branches. Discussion: https://postgr.es/m/CABNQVagu3bZGqiTjb31a8D5Od3fUMs7Oh3gmZMQZVHZ=uWWWfQ@mail.gmail.com Discussion: https://postgr.es/m/1488389.1631984807@sss.pgh.pa.us
This commit is contained in:
parent
c9d07ee376
commit
f230614da2
@ -752,25 +752,33 @@ coerce_type_typmod(Node *node, Oid targetTypeId, int32 targetTypMod,
|
|||||||
CoercionPathType pathtype;
|
CoercionPathType pathtype;
|
||||||
Oid funcId;
|
Oid funcId;
|
||||||
|
|
||||||
/*
|
/* Skip coercion if already done */
|
||||||
* A negative typmod is assumed to mean that no coercion is wanted. Also,
|
if (targetTypMod == exprTypmod(node))
|
||||||
* skip coercion if already done.
|
|
||||||
*/
|
|
||||||
if (targetTypMod < 0 || targetTypMod == exprTypmod(node))
|
|
||||||
return node;
|
return node;
|
||||||
|
|
||||||
|
/* Suppress display of nested coercion steps */
|
||||||
|
if (hideInputCoercion)
|
||||||
|
hide_coercion_node(node);
|
||||||
|
|
||||||
pathtype = find_typmod_coercion_function(targetTypeId, &funcId);
|
pathtype = find_typmod_coercion_function(targetTypeId, &funcId);
|
||||||
|
|
||||||
if (pathtype != COERCION_PATH_NONE)
|
if (pathtype != COERCION_PATH_NONE)
|
||||||
{
|
{
|
||||||
/* Suppress display of nested coercion steps */
|
|
||||||
if (hideInputCoercion)
|
|
||||||
hide_coercion_node(node);
|
|
||||||
|
|
||||||
node = build_coercion_expression(node, pathtype, funcId,
|
node = build_coercion_expression(node, pathtype, funcId,
|
||||||
targetTypeId, targetTypMod,
|
targetTypeId, targetTypMod,
|
||||||
ccontext, cformat, location);
|
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;
|
return node;
|
||||||
}
|
}
|
||||||
|
@ -75,3 +75,40 @@ SELECT current_schema;
|
|||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
RESET search_path;
|
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;
|
||||||
|
@ -34,3 +34,23 @@ SELECT current_schema;
|
|||||||
SET search_path = 'pg_catalog';
|
SET search_path = 'pg_catalog';
|
||||||
SELECT current_schema;
|
SELECT current_schema;
|
||||||
RESET search_path;
|
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;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user