Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 5ebc9c9

Browse files
committed
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
1 parent fbf9a7a commit 5ebc9c9

File tree

3 files changed

+24
-8
lines changed

3 files changed

+24
-8
lines changed

src/backend/utils/adt/timestamp.c

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1509,17 +1509,23 @@ AdjustIntervalForTypmod(Interval *interval, int32 typmod,
15091509

15101510
if (interval->time >= INT64CONST(0))
15111511
{
1512-
interval->time = ((interval->time +
1513-
IntervalOffsets[precision]) /
1514-
IntervalScales[precision]) *
1515-
IntervalScales[precision];
1512+
if (pg_add_s64_overflow(interval->time,
1513+
IntervalOffsets[precision],
1514+
&interval->time))
1515+
ereturn(escontext, false,
1516+
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
1517+
errmsg("interval out of range")));
1518+
interval->time -= interval->time % IntervalScales[precision];
15161519
}
15171520
else
15181521
{
1519-
interval->time = -(((-interval->time +
1520-
IntervalOffsets[precision]) /
1521-
IntervalScales[precision]) *
1522-
IntervalScales[precision]);
1522+
if (pg_sub_s64_overflow(interval->time,
1523+
IntervalOffsets[precision],
1524+
&interval->time))
1525+
ereturn(escontext, false,
1526+
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
1527+
errmsg("interval out of range")));
1528+
interval->time -= interval->time % IntervalScales[precision];
15231529
}
15241530
}
15251531
}

src/test/regress/expected/interval.out

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -929,6 +929,14 @@ SELECT interval '1 2:03:04.5678' minute to second(2);
929929
1 day 02:03:04.57
930930
(1 row)
931931

932+
SELECT interval '2562047788:00:54.775807' second(2); -- out of range
933+
ERROR: interval out of range
934+
LINE 1: SELECT interval '2562047788:00:54.775807' second(2);
935+
^
936+
SELECT interval '-2562047788:00:54.775807' second(2); -- out of range
937+
ERROR: interval out of range
938+
LINE 1: SELECT interval '-2562047788:00:54.775807' second(2);
939+
^
932940
-- test casting to restricted precision (bug #14479)
933941
SELECT f1, f1::INTERVAL DAY TO MINUTE AS "minutes",
934942
(f1 + INTERVAL '1 month')::INTERVAL MONTH::INTERVAL YEAR AS "years"

src/test/regress/sql/interval.sql

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,8 @@ SELECT interval '1 2:03:04.5678' hour to second(2);
270270
SELECT interval '1 2.3456' minute to second(2);
271271
SELECT interval '1 2:03.5678' minute to second(2);
272272
SELECT interval '1 2:03:04.5678' minute to second(2);
273+
SELECT interval '2562047788:00:54.775807' second(2); -- out of range
274+
SELECT interval '-2562047788:00:54.775807' second(2); -- out of range
273275

274276
-- test casting to restricted precision (bug #14479)
275277
SELECT f1, f1::INTERVAL DAY TO MINUTE AS "minutes",

0 commit comments

Comments
 (0)