#error -ffast-math is known to break this code
#endif
+#define SAMESIGN(a,b) (((a) < 0) == ((b) < 0))
+
+#ifndef INT64_MAX
+#define INT64_MAX INT64CONST(0x7FFFFFFFFFFFFFFF)
+#endif
+
+#ifndef INT64_MIN
+#define INT64_MIN (-INT64CONST(0x7FFFFFFFFFFFFFFF) - 1)
+#endif
/* Set at postmaster start */
TimestampTz PgStartTime;
#ifdef HAVE_INT64_TIMESTAMP
tfrac = time / USECS_PER_HOUR;
time -= tfrac * USECS_PER_HOUR;
- tm->tm_hour = tfrac; /* could overflow ... */
+ tm->tm_hour = tfrac;
+ if (!SAMESIGN(tm->tm_hour, tfrac))
+ ereport(ERROR,
+ (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
+ errmsg("interval out of range")));
tfrac = time / USECS_PER_MINUTE;
time -= tfrac * USECS_PER_MINUTE;
tm->tm_min = tfrac;
int
tm2interval(struct pg_tm * tm, fsec_t fsec, Interval *span)
{
- span->month = tm->tm_year * MONTHS_PER_YEAR + tm->tm_mon;
+ double total_months = (double)tm->tm_year * MONTHS_PER_YEAR + tm->tm_mon;
+
+ if (total_months > INT_MAX || total_months < INT_MIN)
+ return -1;
+ span->month = total_months;
span->day = tm->tm_mday;
#ifdef HAVE_INT64_TIMESTAMP
span->time = (((((tm->tm_hour * INT64CONST(60)) +
result = (Interval *) palloc(sizeof(Interval));
result->time = -interval->time;
+ /* overflow check copied from int4um */
+ if (interval->time != 0 && SAMESIGN(result->time, interval->time))
+ ereport(ERROR,
+ (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
+ errmsg("interval out of range")));
result->day = -interval->day;
+ if (interval->day != 0 && SAMESIGN(result->day, interval->day))
+ ereport(ERROR,
+ (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
+ errmsg("interval out of range")));
result->month = -interval->month;
+ if (interval->month != 0 && SAMESIGN(result->month, interval->month))
+ ereport(ERROR,
+ (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
+ errmsg("interval out of range")));
PG_RETURN_INTERVAL_P(result);
}
result = (Interval *) palloc(sizeof(Interval));
result->month = span1->month + span2->month;
+ /* overflow check copied from int4pl */
+ if (SAMESIGN(span1->month, span2->month) &&
+ !SAMESIGN(result->month, span1->month))
+ ereport(ERROR,
+ (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
+ errmsg("interval out of range")));
+
result->day = span1->day + span2->day;
+ if (SAMESIGN(span1->day, span2->day) &&
+ !SAMESIGN(result->day, span1->day))
+ ereport(ERROR,
+ (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
+ errmsg("interval out of range")));
+
result->time = span1->time + span2->time;
+ if (SAMESIGN(span1->time, span2->time) &&
+ !SAMESIGN(result->time, span1->time))
+ ereport(ERROR,
+ (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
+ errmsg("interval out of range")));
PG_RETURN_INTERVAL_P(result);
}
result = (Interval *) palloc(sizeof(Interval));
result->month = span1->month - span2->month;
+ /* overflow check copied from int4mi */
+ if (!SAMESIGN(span1->month, span2->month) &&
+ !SAMESIGN(result->month, span1->month))
+ ereport(ERROR,
+ (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
+ errmsg("interval out of range")));
+
result->day = span1->day - span2->day;
+ if (!SAMESIGN(span1->day, span2->day) &&
+ !SAMESIGN(result->day, span1->day))
+ ereport(ERROR,
+ (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
+ errmsg("interval out of range")));
+
result->time = span1->time - span2->time;
+ if (!SAMESIGN(span1->time, span2->time) &&
+ !SAMESIGN(result->time, span1->time))
+ ereport(ERROR,
+ (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
+ errmsg("interval out of range")));
+
PG_RETURN_INTERVAL_P(result);
}
Interval *span = PG_GETARG_INTERVAL_P(0);
float8 factor = PG_GETARG_FLOAT8(1);
double month_remainder_days,
- sec_remainder;
+ sec_remainder,
+ result_double;
int32 orig_month = span->month,
orig_day = span->day;
Interval *result;
result = (Interval *) palloc(sizeof(Interval));
- result->month = (int32) (span->month * factor);
- result->day = (int32) (span->day * factor);
+ result_double = span->month * factor;
+ if (result_double > INT_MAX || result_double < INT_MIN)
+ ereport(ERROR,
+ (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
+ errmsg("interval out of range")));
+ result->month = (int32) result_double;
+
+ result_double = span->day * factor;
+ if (result_double > INT_MAX || result_double < INT_MIN)
+ ereport(ERROR,
+ (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
+ errmsg("interval out of range")));
+ result->day = (int32) result_double;
/*
* The above correctly handles the whole-number part of the month and day
/* cascade units down */
result->day += (int32) month_remainder_days;
#ifdef HAVE_INT64_TIMESTAMP
- result->time = rint(span->time * factor + sec_remainder * USECS_PER_SEC);
+ result_double = rint(span->time * factor + sec_remainder * USECS_PER_SEC);
+ if (result_double > INT64_MAX || result_double < INT64_MIN)
+ ereport(ERROR,
+ (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
+ errmsg("interval out of range")));
+ result->time = (int64) result_double;
#else
result->time = span->time * factor + sec_remainder;
#endif