mirror of
https://github.com/postgres/postgres.git
synced 2025-05-02 11:44:50 +03:00
Avoid integer overflow hazard in interval_time().
When casting an interval to a time, the original code suffered from 64-bit integer overflow for inputs with a sufficiently large negative "time" field, leading to bogus results. Fix by rewriting the algorithm in a simpler form, that more obviously cannot overflow. While at it, improve the test coverage to include negative interval inputs. Discussion: https://postgr.es/m/CAEZATCXoUKHkcuq4q63hkiPsKZJd0kZWzgKtU%2BNT0aU4wbf_Pw%40mail.gmail.com
This commit is contained in:
parent
a4f7d33a90
commit
3850d4dec1
@ -2012,19 +2012,10 @@ interval_time(PG_FUNCTION_ARGS)
|
|||||||
{
|
{
|
||||||
Interval *span = PG_GETARG_INTERVAL_P(0);
|
Interval *span = PG_GETARG_INTERVAL_P(0);
|
||||||
TimeADT result;
|
TimeADT result;
|
||||||
int64 days;
|
|
||||||
|
|
||||||
result = span->time;
|
result = span->time % USECS_PER_DAY;
|
||||||
if (result >= USECS_PER_DAY)
|
if (result < 0)
|
||||||
{
|
result += USECS_PER_DAY;
|
||||||
days = result / USECS_PER_DAY;
|
|
||||||
result -= days * USECS_PER_DAY;
|
|
||||||
}
|
|
||||||
else if (result < 0)
|
|
||||||
{
|
|
||||||
days = (-result + USECS_PER_DAY - 1) / USECS_PER_DAY;
|
|
||||||
result += days * USECS_PER_DAY;
|
|
||||||
}
|
|
||||||
|
|
||||||
PG_RETURN_TIMEADT(result);
|
PG_RETURN_TIMEADT(result);
|
||||||
}
|
}
|
||||||
|
@ -981,6 +981,18 @@ SELECT CAST(interval '02:03' AS time) AS "02:03:00";
|
|||||||
02:03:00
|
02:03:00
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
|
SELECT CAST(interval '-02:03' AS time) AS "21:57:00";
|
||||||
|
21:57:00
|
||||||
|
----------
|
||||||
|
21:57:00
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT CAST(interval '-9223372022400000000 us' AS time) AS "00:00:00";
|
||||||
|
00:00:00
|
||||||
|
----------
|
||||||
|
00:00:00
|
||||||
|
(1 row)
|
||||||
|
|
||||||
SELECT time '01:30' + interval '02:01' AS "03:31:00";
|
SELECT time '01:30' + interval '02:01' AS "03:31:00";
|
||||||
03:31:00
|
03:31:00
|
||||||
----------
|
----------
|
||||||
|
@ -182,6 +182,8 @@ SELECT d1 - interval '1 year' AS one_year FROM TIMESTAMPTZ_TBL;
|
|||||||
|
|
||||||
SELECT CAST(time '01:02' AS interval) AS "+01:02";
|
SELECT CAST(time '01:02' AS interval) AS "+01:02";
|
||||||
SELECT CAST(interval '02:03' AS time) AS "02:03:00";
|
SELECT CAST(interval '02:03' AS time) AS "02:03:00";
|
||||||
|
SELECT CAST(interval '-02:03' AS time) AS "21:57:00";
|
||||||
|
SELECT CAST(interval '-9223372022400000000 us' AS time) AS "00:00:00";
|
||||||
SELECT time '01:30' + interval '02:01' AS "03:31:00";
|
SELECT time '01:30' + interval '02:01' AS "03:31:00";
|
||||||
SELECT time '01:30' - interval '02:01' AS "23:29:00";
|
SELECT time '01:30' - interval '02:01' AS "23:29:00";
|
||||||
SELECT time '02:30' + interval '36:01' AS "14:31:00";
|
SELECT time '02:30' + interval '36:01' AS "14:31:00";
|
||||||
|
Loading…
x
Reference in New Issue
Block a user