1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-27 23:21:58 +03:00

Detect overflow in timestamp[tz] subtraction.

It's possible to overflow the int64 microseconds field of the
output interval when subtracting two timestamps.  Detect that
instead of silently returning a bogus result.

Nick Babadzhanian

Discussion: https://postgr.es/m/CABw73Uq2oJ3E+kYvvDuY04EkhhkChim2e-PaghBDjOmgUAMWGw@mail.gmail.com
This commit is contained in:
Tom Lane
2023-02-20 17:26:25 -05:00
parent f0d0394e84
commit 8028e294b4
5 changed files with 30 additions and 1 deletions

View File

@ -2713,7 +2713,10 @@ timestamp_mi(PG_FUNCTION_ARGS)
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("cannot subtract infinite timestamps"))); errmsg("cannot subtract infinite timestamps")));
result->time = dt1 - dt2; if (unlikely(pg_sub_s64_overflow(dt1, dt2, &result->time)))
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("interval out of range")));
result->month = 0; result->month = 0;
result->day = 0; result->day = 0;

View File

@ -1207,6 +1207,15 @@ SELECT extract(epoch from '5000-01-01 00:00:00'::timestamp);
95617584000.000000 95617584000.000000
(1 row) (1 row)
-- test edge-case overflow in timestamp subtraction
SELECT timestamp '294276-12-31 23:59:59' - timestamp '1999-12-23 19:59:04.224193' AS ok;
ok
-----------------------------------------
@ 106751991 days 4 hours 54.775807 secs
(1 row)
SELECT timestamp '294276-12-31 23:59:59' - timestamp '1999-12-23 19:59:04.224192' AS overflows;
ERROR: interval out of range
-- TO_CHAR() -- TO_CHAR()
SELECT to_char(d1, 'DAY Day day DY Dy dy MONTH Month month RM MON Mon mon') SELECT to_char(d1, 'DAY Day day DY Dy dy MONTH Month month RM MON Mon mon')
FROM TIMESTAMP_TBL; FROM TIMESTAMP_TBL;

View File

@ -1331,6 +1331,15 @@ SELECT extract(epoch from '5000-01-01 00:00:00+00'::timestamptz);
95617584000.000000 95617584000.000000
(1 row) (1 row)
-- test edge-case overflow in timestamp subtraction
SELECT timestamptz '294276-12-31 23:59:59 UTC' - timestamptz '1999-12-23 19:59:04.224193 UTC' AS ok;
ok
-----------------------------------------
@ 106751991 days 4 hours 54.775807 secs
(1 row)
SELECT timestamptz '294276-12-31 23:59:59 UTC' - timestamptz '1999-12-23 19:59:04.224192 UTC' AS overflows;
ERROR: interval out of range
-- TO_CHAR() -- TO_CHAR()
SELECT to_char(d1, 'DAY Day day DY Dy dy MONTH Month month RM MON Mon mon') SELECT to_char(d1, 'DAY Day day DY Dy dy MONTH Month month RM MON Mon mon')
FROM TIMESTAMPTZ_TBL; FROM TIMESTAMPTZ_TBL;

View File

@ -326,6 +326,10 @@ SELECT extract(epoch from '294270-01-01 00:00:00'::timestamp);
-- another internal overflow test case -- another internal overflow test case
SELECT extract(epoch from '5000-01-01 00:00:00'::timestamp); SELECT extract(epoch from '5000-01-01 00:00:00'::timestamp);
-- test edge-case overflow in timestamp subtraction
SELECT timestamp '294276-12-31 23:59:59' - timestamp '1999-12-23 19:59:04.224193' AS ok;
SELECT timestamp '294276-12-31 23:59:59' - timestamp '1999-12-23 19:59:04.224192' AS overflows;
-- TO_CHAR() -- TO_CHAR()
SELECT to_char(d1, 'DAY Day day DY Dy dy MONTH Month month RM MON Mon mon') SELECT to_char(d1, 'DAY Day day DY Dy dy MONTH Month month RM MON Mon mon')
FROM TIMESTAMP_TBL; FROM TIMESTAMP_TBL;

View File

@ -306,6 +306,10 @@ SELECT extract(epoch from '294270-01-01 00:00:00+00'::timestamptz);
-- another internal overflow test case -- another internal overflow test case
SELECT extract(epoch from '5000-01-01 00:00:00+00'::timestamptz); SELECT extract(epoch from '5000-01-01 00:00:00+00'::timestamptz);
-- test edge-case overflow in timestamp subtraction
SELECT timestamptz '294276-12-31 23:59:59 UTC' - timestamptz '1999-12-23 19:59:04.224193 UTC' AS ok;
SELECT timestamptz '294276-12-31 23:59:59 UTC' - timestamptz '1999-12-23 19:59:04.224192 UTC' AS overflows;
-- TO_CHAR() -- TO_CHAR()
SELECT to_char(d1, 'DAY Day day DY Dy dy MONTH Month month RM MON Mon mon') SELECT to_char(d1, 'DAY Day day DY Dy dy MONTH Month month RM MON Mon mon')
FROM TIMESTAMPTZ_TBL; FROM TIMESTAMPTZ_TBL;