aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/adt/timestamp.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/utils/adt/timestamp.c')
-rw-r--r--src/backend/utils/adt/timestamp.c35
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)
{