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

Remove dependence on -fwrapv semantics in a few places.

This commit attempts to update a few places, such as the money,
numeric, and timestamp types, to no longer rely on signed integer
wrapping for correctness.  This is intended to move us closer
towards removing -fwrapv, which may enable some compiler
optimizations.  However, there is presently no plan to actually
remove that compiler option in the near future.

Besides using some of the existing overflow-aware routines in
int.h, this commit introduces and makes use of some new ones.
Specifically, it adds functions that accept a signed integer and
return its absolute value as an unsigned integer with the same
width (e.g., pg_abs_s64()).  It also adds functions that accept an
unsigned integer, store the result of negating that integer in a
signed integer with the same width, and return whether the negation
overflowed (e.g., pg_neg_u64_overflow()).

Finally, this commit adds a couple of tests for timestamps near
POSTGRES_EPOCH_JDATE.

Author: Joseph Koshakow
Reviewed-by: Tom Lane, Heikki Linnakangas, Jian He
Discussion: https://postgr.es/m/CAAvxfHdBPOyEGS7s%2Bxf4iaW0-cgiq25jpYdWBqQqvLtLe_t6tw%40mail.gmail.com
This commit is contained in:
Nathan Bossart
2024-08-15 15:47:31 -05:00
parent ad89d71978
commit 9e9a2b7031
10 changed files with 189 additions and 65 deletions

View File

@ -618,19 +618,8 @@ make_timestamp_internal(int year, int month, int day,
time = (((hour * MINS_PER_HOUR + min) * SECS_PER_MINUTE)
* USECS_PER_SEC) + (int64) rint(sec * USECS_PER_SEC);
result = date * USECS_PER_DAY + time;
/* check for major overflow */
if ((result - time) / USECS_PER_DAY != date)
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range: %d-%02d-%02d %d:%02d:%02g",
year, month, day,
hour, min, sec)));
/* check for just-barely overflow (okay except time-of-day wraps) */
/* caution: we want to allow 1999-12-31 24:00:00 */
if ((result < 0 && date > 0) ||
(result > 0 && date < -1))
if (unlikely(pg_mul_s64_overflow(date, USECS_PER_DAY, &result) ||
pg_add_s64_overflow(result, time, &result)))
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range: %d-%02d-%02d %d:%02d:%02g",
@ -2010,17 +1999,8 @@ tm2timestamp(struct pg_tm *tm, fsec_t fsec, int *tzp, Timestamp *result)
date = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE;
time = time2t(tm->tm_hour, tm->tm_min, tm->tm_sec, fsec);
*result = date * USECS_PER_DAY + time;
/* check for major overflow */
if ((*result - time) / USECS_PER_DAY != date)
{
*result = 0; /* keep compiler quiet */
return -1;
}
/* check for just-barely overflow (okay except time-of-day wraps) */
/* caution: we want to allow 1999-12-31 24:00:00 */
if ((*result < 0 && date > 0) ||
(*result > 0 && date < -1))
if (unlikely(pg_mul_s64_overflow(date, USECS_PER_DAY, result) ||
pg_add_s64_overflow(*result, time, result)))
{
*result = 0; /* keep compiler quiet */
return -1;