mirror of
https://github.com/postgres/postgres.git
synced 2025-04-21 12:05:57 +03:00
Catch overflow when rounding intervals in AdjustIntervalForTypmod.
Previously, an interval microseconds field close to INT64_MAX or INT64_MIN could overflow, producing a result with not even the correct sign, while being rounded to match a precision specification. This seems worth fixing, but not worth back-patching, in part because the ereturn() notation doesn't exist very far back. Report and patch by Joseph Koshakow (some cosmetic mods by me) Discussion: https://postgr.es/m/CAAvxfHfpuLgqJYzkUcher466Z1LpmE+5Sm+zc8L6zKCOQ+6TDQ@mail.gmail.com
This commit is contained in:
parent
fbf9a7ac4d
commit
5ebc9c9017
@ -1509,17 +1509,23 @@ AdjustIntervalForTypmod(Interval *interval, int32 typmod,
|
||||
|
||||
if (interval->time >= INT64CONST(0))
|
||||
{
|
||||
interval->time = ((interval->time +
|
||||
IntervalOffsets[precision]) /
|
||||
IntervalScales[precision]) *
|
||||
IntervalScales[precision];
|
||||
if (pg_add_s64_overflow(interval->time,
|
||||
IntervalOffsets[precision],
|
||||
&interval->time))
|
||||
ereturn(escontext, false,
|
||||
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
||||
errmsg("interval out of range")));
|
||||
interval->time -= interval->time % IntervalScales[precision];
|
||||
}
|
||||
else
|
||||
{
|
||||
interval->time = -(((-interval->time +
|
||||
IntervalOffsets[precision]) /
|
||||
IntervalScales[precision]) *
|
||||
IntervalScales[precision]);
|
||||
if (pg_sub_s64_overflow(interval->time,
|
||||
IntervalOffsets[precision],
|
||||
&interval->time))
|
||||
ereturn(escontext, false,
|
||||
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
|
||||
errmsg("interval out of range")));
|
||||
interval->time -= interval->time % IntervalScales[precision];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -929,6 +929,14 @@ SELECT interval '1 2:03:04.5678' minute to second(2);
|
||||
1 day 02:03:04.57
|
||||
(1 row)
|
||||
|
||||
SELECT interval '2562047788:00:54.775807' second(2); -- out of range
|
||||
ERROR: interval out of range
|
||||
LINE 1: SELECT interval '2562047788:00:54.775807' second(2);
|
||||
^
|
||||
SELECT interval '-2562047788:00:54.775807' second(2); -- out of range
|
||||
ERROR: interval out of range
|
||||
LINE 1: SELECT interval '-2562047788:00:54.775807' 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"
|
||||
|
@ -270,6 +270,8 @@ SELECT interval '1 2:03:04.5678' hour to second(2);
|
||||
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);
|
||||
SELECT interval '2562047788:00:54.775807' second(2); -- out of range
|
||||
SELECT interval '-2562047788:00:54.775807' second(2); -- out of range
|
||||
|
||||
-- test casting to restricted precision (bug #14479)
|
||||
SELECT f1, f1::INTERVAL DAY TO MINUTE AS "minutes",
|
||||
|
Loading…
x
Reference in New Issue
Block a user