diff --git a/src/common/backend/utils/adt/timestamp.cpp b/src/common/backend/utils/adt/timestamp.cpp index ebb8c9e4d..5a65cad13 100644 --- a/src/common/backend/utils/adt/timestamp.cpp +++ b/src/common/backend/utils/adt/timestamp.cpp @@ -35,6 +35,7 @@ #include "utils/builtins.h" #include "utils/datetime.h" #include "utils/formatting.h" +#include "common/int.h" #ifdef PGXC #include "pgxc/pgxc.h" @@ -2600,9 +2601,7 @@ Datum interval_justify_interval(PG_FUNCTION_ARGS) #else TMODULO(result->time, wholeday, (double)SECS_PER_DAY); #endif - if (MAX_INT32 - result->day > wholeday) { - result->day += wholeday; - } else { + if (pg_add_s32_overflow(result->day, wholeday, &result->day)) { ereport(ERROR, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); } diff --git a/src/test/regress/expected/interval.out b/src/test/regress/expected/interval.out index 3415a386d..f418ff6d8 100644 --- a/src/test/regress/expected/interval.out +++ b/src/test/regress/expected/interval.out @@ -342,6 +342,44 @@ SELECT justify_interval(interval '1 month -1 hour') as "1 month -1 hour"; @ 29 days 23 hours (1 row) +SELECT justify_interval('5 mon -50 days'::interval); + justify_interval +------------------ + @ 3 mons 10 days +(1 row) + +SELECT justify_interval('1 mon -47 days'::interval); + justify_interval +------------------ + @ 17 days ago +(1 row) + +SELECT justify_interval('1 mon -48 days'::interval); + justify_interval +------------------ + @ 18 days ago +(1 row) + +SELECT justify_interval('1 mon -48 days'::interval); + justify_interval +------------------ + @ 18 days ago +(1 row) + +select justify_interval('5 mon -2147483648 days'::interval); + justify_interval +------------------------------------ + @ 5965231 years 11 mons 8 days ago +(1 row) + +select justify_interval('5 mon -2147483648 days -128 hours'::interval); +ERROR: timestamp out of range +CONTEXT: referenced column: justify_interval +select justify_interval('5 mon -2147483649 days'::interval); +ERROR: interval field value out of range: "5 mon -2147483649 days" +LINE 1: select justify_interval('5 mon -2147483649 days'::interval); + ^ +CONTEXT: referenced column: justify_interval -- test fractional second input, and detection of duplicate units SET DATESTYLE = 'ISO'; SET IntervalStyle TO postgres; diff --git a/src/test/regress/sql/interval.sql b/src/test/regress/sql/interval.sql index 026234576..7f3b7aea6 100644 --- a/src/test/regress/sql/interval.sql +++ b/src/test/regress/sql/interval.sql @@ -122,6 +122,14 @@ SELECT justify_days(interval '6 months 36 days 5 hours 4 minutes 3 seconds') as SELECT justify_interval(interval '1 month -1 hour') as "1 month -1 hour"; +SELECT justify_interval('5 mon -50 days'::interval); +SELECT justify_interval('1 mon -47 days'::interval); +SELECT justify_interval('1 mon -48 days'::interval); +SELECT justify_interval('1 mon -48 days'::interval); +select justify_interval('5 mon -2147483648 days'::interval); +select justify_interval('5 mon -2147483648 days -128 hours'::interval); +select justify_interval('5 mon -2147483649 days'::interval); + -- test fractional second input, and detection of duplicate units SET DATESTYLE = 'ISO'; SET IntervalStyle TO postgres;