Thanks to visit codestin.com
Credit goes to github.com

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)