1
0
mirror of https://github.com/postgres/postgres.git synced 2025-08-31 17:02: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

@@ -11,6 +11,7 @@
#error -ffast-math is known to break this code
#endif
#include "common/int.h"
#include "dt.h"
#include "pgtypes_date.h"
#include "pgtypes_timestamp.h"
@@ -48,14 +49,8 @@ tm2timestamp(struct tm *tm, fsec_t fsec, int *tzp, timestamp * result)
dDate = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j(2000, 1, 1);
time = time2t(tm->tm_hour, tm->tm_min, tm->tm_sec, fsec);
*result = (dDate * USECS_PER_DAY) + time;
/* check for major overflow */
if ((*result - time) / USECS_PER_DAY != dDate)
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 && dDate > 0) ||
(*result > 0 && dDate < -1))
if (unlikely(pg_mul_s64_overflow(dDate, USECS_PER_DAY, result) ||
pg_add_s64_overflow(*result, time, result)))
return -1;
if (tzp != NULL)
*result = dt2local(*result, -(*tzp));