diff options
Diffstat (limited to 'src/backend/utils/adt/timestamp.c')
-rw-r--r-- | src/backend/utils/adt/timestamp.c | 35 |
1 files changed, 31 insertions, 4 deletions
diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c index 36f8a84bcc5..ae36ff33285 100644 --- a/src/backend/utils/adt/timestamp.c +++ b/src/backend/utils/adt/timestamp.c @@ -2717,12 +2717,33 @@ interval_justify_interval(PG_FUNCTION_ARGS) result->day = span->day; result->time = span->time; + /* pre-justify days if it might prevent overflow */ + if ((result->day > 0 && result->time > 0) || + (result->day < 0 && result->time < 0)) + { + wholemonth = result->day / DAYS_PER_MONTH; + result->day -= wholemonth * DAYS_PER_MONTH; + if (pg_add_s32_overflow(result->month, wholemonth, &result->month)) + ereport(ERROR, + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("interval out of range"))); + } + + /* + * Since TimeOffset is int64, abs(wholeday) can't exceed about 1.07e8. If + * we pre-justified then abs(result->day) is less than DAYS_PER_MONTH, so + * this addition can't overflow. If we didn't pre-justify, then day and + * time are of different signs, so it still can't overflow. + */ TMODULO(result->time, wholeday, USECS_PER_DAY); - result->day += wholeday; /* could overflow... */ + result->day += wholeday; wholemonth = result->day / DAYS_PER_MONTH; result->day -= wholemonth * DAYS_PER_MONTH; - result->month += wholemonth; + if (pg_add_s32_overflow(result->month, wholemonth, &result->month)) + ereport(ERROR, + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("interval out of range"))); if (result->month > 0 && (result->day < 0 || (result->day == 0 && result->time < 0))) @@ -2772,7 +2793,10 @@ interval_justify_hours(PG_FUNCTION_ARGS) result->time = span->time; TMODULO(result->time, wholeday, USECS_PER_DAY); - result->day += wholeday; /* could overflow... */ + if (pg_add_s32_overflow(result->day, wholeday, &result->day)) + ereport(ERROR, + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("interval out of range"))); if (result->day > 0 && result->time < 0) { @@ -2808,7 +2832,10 @@ interval_justify_days(PG_FUNCTION_ARGS) wholemonth = result->day / DAYS_PER_MONTH; result->day -= wholemonth * DAYS_PER_MONTH; - result->month += wholemonth; + if (pg_add_s32_overflow(result->month, wholemonth, &result->month)) + ereport(ERROR, + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("interval out of range"))); if (result->month > 0 && result->day < 0) { |