diff options
| author | Tom Lane | 2016-12-27 20:43:54 +0000 |
|---|---|---|
| committer | Tom Lane | 2016-12-27 20:43:54 +0000 |
| commit | f0774abde868e0b5a2acbe75b5028884752f739d (patch) | |
| tree | bf971fb394d08cb21875dbdfa2a1f9065c23a97c /src/test | |
| parent | 71f996d22125eb6cfdbee6094f44370aa8dec610 (diff) | |
Fix interval_transform so it doesn't throw away non-no-op casts.
interval_transform() contained two separate bugs that caused it to
sometimes mistakenly decide that a cast from interval to restricted
interval is a no-op and throw it away.
First, it was wrong to rely on dt.h's field type macros to have an
ordering consistent with the field's significance; in one case they do
not. This led to mistakenly treating YEAR as less significant than MONTH,
so that a cast from INTERVAL MONTH to INTERVAL YEAR was incorrectly
discarded.
Second, fls(1<<k) produces k+1 not k, so comparing its output directly
to SECOND was wrong. This led to supposing that a cast to INTERVAL
MINUTE was really a cast to INTERVAL SECOND and so could be discarded.
To fix, get rid of the use of fls(), and make a function based on
intervaltypmodout to produce a field ID code adapted to the need here.
Per bug #14479 from Piotr Stefaniak. Back-patch to 9.2 where transform
functions were introduced, because this code was born broken.
Discussion: https://postgr.es/m/20161227172307.10135.7747@wrigleys.postgresql.org
Diffstat (limited to 'src/test')
| -rw-r--r-- | src/test/regress/expected/interval.out | 18 | ||||
| -rw-r--r-- | src/test/regress/sql/interval.sql | 5 |
2 files changed, 23 insertions, 0 deletions
diff --git a/src/test/regress/expected/interval.out b/src/test/regress/expected/interval.out index c873a99bd94..946c97ad924 100644 --- a/src/test/regress/expected/interval.out +++ b/src/test/regress/expected/interval.out @@ -682,6 +682,24 @@ SELECT interval '1 2:03:04.5678' minute to second(2); 1 day 02:03:04.57 (1 row) +-- test casting to restricted precision (bug #14479) +SELECT f1, f1::INTERVAL DAY TO MINUTE AS "minutes", + (f1 + INTERVAL '1 month')::INTERVAL MONTH::INTERVAL YEAR AS "years" + FROM interval_tbl; + f1 | minutes | years +-----------------+-----------------+---------- + 00:01:00 | 00:01:00 | 00:00:00 + 05:00:00 | 05:00:00 | 00:00:00 + 10 days | 10 days | 00:00:00 + 34 years | 34 years | 34 years + 3 mons | 3 mons | 00:00:00 + -00:00:14 | 00:00:00 | 00:00:00 + 1 day 02:03:04 | 1 day 02:03:00 | 00:00:00 + 6 years | 6 years | 6 years + 5 mons | 5 mons | 00:00:00 + 5 mons 12:00:00 | 5 mons 12:00:00 | 00:00:00 +(10 rows) + -- test inputting and outputting SQL standard interval literals SET IntervalStyle TO sql_standard; SELECT interval '0' AS "zero", diff --git a/src/test/regress/sql/interval.sql b/src/test/regress/sql/interval.sql index 789c3de4403..cff9adab321 100644 --- a/src/test/regress/sql/interval.sql +++ b/src/test/regress/sql/interval.sql @@ -196,6 +196,11 @@ SELECT interval '1 2.3456' minute to second(2); SELECT interval '1 2:03.5678' minute to second(2); SELECT interval '1 2:03:04.5678' minute to second(2); +-- test casting to restricted precision (bug #14479) +SELECT f1, f1::INTERVAL DAY TO MINUTE AS "minutes", + (f1 + INTERVAL '1 month')::INTERVAL MONTH::INTERVAL YEAR AS "years" + FROM interval_tbl; + -- test inputting and outputting SQL standard interval literals SET IntervalStyle TO sql_standard; SELECT interval '0' AS "zero", |
