mirror of
				https://github.com/postgres/postgres.git
				synced 2025-11-03 09:13:20 +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:
		@@ -387,6 +387,7 @@ Datum
 | 
			
		||||
cash_out(PG_FUNCTION_ARGS)
 | 
			
		||||
{
 | 
			
		||||
	Cash		value = PG_GETARG_CASH(0);
 | 
			
		||||
	uint64		uvalue;
 | 
			
		||||
	char	   *result;
 | 
			
		||||
	char		buf[128];
 | 
			
		||||
	char	   *bufptr;
 | 
			
		||||
@@ -429,8 +430,6 @@ cash_out(PG_FUNCTION_ARGS)
 | 
			
		||||
 | 
			
		||||
	if (value < 0)
 | 
			
		||||
	{
 | 
			
		||||
		/* make the amount positive for digit-reconstruction loop */
 | 
			
		||||
		value = -value;
 | 
			
		||||
		/* set up formatting data */
 | 
			
		||||
		signsymbol = (*lconvert->negative_sign != '\0') ? lconvert->negative_sign : "-";
 | 
			
		||||
		sign_posn = lconvert->n_sign_posn;
 | 
			
		||||
@@ -445,6 +444,9 @@ cash_out(PG_FUNCTION_ARGS)
 | 
			
		||||
		sep_by_space = lconvert->p_sep_by_space;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* make the amount positive for digit-reconstruction loop */
 | 
			
		||||
	uvalue = pg_abs_s64(value);
 | 
			
		||||
 | 
			
		||||
	/* we build the digits+decimal-point+sep string right-to-left in buf[] */
 | 
			
		||||
	bufptr = buf + sizeof(buf) - 1;
 | 
			
		||||
	*bufptr = '\0';
 | 
			
		||||
@@ -470,10 +472,10 @@ cash_out(PG_FUNCTION_ARGS)
 | 
			
		||||
			memcpy(bufptr, ssymbol, strlen(ssymbol));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		*(--bufptr) = ((uint64) value % 10) + '0';
 | 
			
		||||
		value = ((uint64) value) / 10;
 | 
			
		||||
		*(--bufptr) = (uvalue % 10) + '0';
 | 
			
		||||
		uvalue = uvalue / 10;
 | 
			
		||||
		digit_pos--;
 | 
			
		||||
	} while (value || digit_pos >= 0);
 | 
			
		||||
	} while (uvalue || digit_pos >= 0);
 | 
			
		||||
 | 
			
		||||
	/*----------
 | 
			
		||||
	 * Now, attach currency symbol and sign symbol in the correct order.
 | 
			
		||||
 
 | 
			
		||||
@@ -8113,7 +8113,7 @@ int64_to_numericvar(int64 val, NumericVar *var)
 | 
			
		||||
	if (val < 0)
 | 
			
		||||
	{
 | 
			
		||||
		var->sign = NUMERIC_NEG;
 | 
			
		||||
		uval = -val;
 | 
			
		||||
		uval = pg_abs_s64(val);
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
@@ -11584,7 +11584,7 @@ power_var_int(const NumericVar *base, int exp, int exp_dscale,
 | 
			
		||||
	 * Now we can proceed with the multiplications.
 | 
			
		||||
	 */
 | 
			
		||||
	neg = (exp < 0);
 | 
			
		||||
	mask = abs(exp);
 | 
			
		||||
	mask = pg_abs_s32(exp);
 | 
			
		||||
 | 
			
		||||
	init_var(&base_prod);
 | 
			
		||||
	set_var_from_var(base, &base_prod);
 | 
			
		||||
 
 | 
			
		||||
@@ -18,6 +18,7 @@
 | 
			
		||||
#include <limits.h>
 | 
			
		||||
#include <ctype.h>
 | 
			
		||||
 | 
			
		||||
#include "common/int.h"
 | 
			
		||||
#include "port/pg_bitutils.h"
 | 
			
		||||
#include "utils/builtins.h"
 | 
			
		||||
 | 
			
		||||
@@ -131,6 +132,7 @@ pg_strtoint16_safe(const char *s, Node *escontext)
 | 
			
		||||
	uint16		tmp = 0;
 | 
			
		||||
	bool		neg = false;
 | 
			
		||||
	unsigned char digit;
 | 
			
		||||
	int16		result;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * The majority of cases are likely to be base-10 digits without any
 | 
			
		||||
@@ -190,10 +192,9 @@ pg_strtoint16_safe(const char *s, Node *escontext)
 | 
			
		||||
 | 
			
		||||
	if (neg)
 | 
			
		||||
	{
 | 
			
		||||
		/* check the negative equivalent will fit without overflowing */
 | 
			
		||||
		if (unlikely(tmp > (uint16) (-(PG_INT16_MIN + 1)) + 1))
 | 
			
		||||
		if (unlikely(pg_neg_u16_overflow(tmp, &result)))
 | 
			
		||||
			goto out_of_range;
 | 
			
		||||
		return -((int16) tmp);
 | 
			
		||||
		return result;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (unlikely(tmp > PG_INT16_MAX))
 | 
			
		||||
@@ -333,10 +334,9 @@ slow:
 | 
			
		||||
 | 
			
		||||
	if (neg)
 | 
			
		||||
	{
 | 
			
		||||
		/* check the negative equivalent will fit without overflowing */
 | 
			
		||||
		if (tmp > (uint16) (-(PG_INT16_MIN + 1)) + 1)
 | 
			
		||||
		if (unlikely(pg_neg_u16_overflow(tmp, &result)))
 | 
			
		||||
			goto out_of_range;
 | 
			
		||||
		return -((int16) tmp);
 | 
			
		||||
		return result;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (tmp > PG_INT16_MAX)
 | 
			
		||||
@@ -393,6 +393,7 @@ pg_strtoint32_safe(const char *s, Node *escontext)
 | 
			
		||||
	uint32		tmp = 0;
 | 
			
		||||
	bool		neg = false;
 | 
			
		||||
	unsigned char digit;
 | 
			
		||||
	int32		result;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * The majority of cases are likely to be base-10 digits without any
 | 
			
		||||
@@ -452,10 +453,9 @@ pg_strtoint32_safe(const char *s, Node *escontext)
 | 
			
		||||
 | 
			
		||||
	if (neg)
 | 
			
		||||
	{
 | 
			
		||||
		/* check the negative equivalent will fit without overflowing */
 | 
			
		||||
		if (unlikely(tmp > (uint32) (-(PG_INT32_MIN + 1)) + 1))
 | 
			
		||||
		if (unlikely(pg_neg_u32_overflow(tmp, &result)))
 | 
			
		||||
			goto out_of_range;
 | 
			
		||||
		return -((int32) tmp);
 | 
			
		||||
		return result;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (unlikely(tmp > PG_INT32_MAX))
 | 
			
		||||
@@ -595,10 +595,9 @@ slow:
 | 
			
		||||
 | 
			
		||||
	if (neg)
 | 
			
		||||
	{
 | 
			
		||||
		/* check the negative equivalent will fit without overflowing */
 | 
			
		||||
		if (tmp > (uint32) (-(PG_INT32_MIN + 1)) + 1)
 | 
			
		||||
		if (unlikely(pg_neg_u32_overflow(tmp, &result)))
 | 
			
		||||
			goto out_of_range;
 | 
			
		||||
		return -((int32) tmp);
 | 
			
		||||
		return result;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (tmp > PG_INT32_MAX)
 | 
			
		||||
@@ -655,6 +654,7 @@ pg_strtoint64_safe(const char *s, Node *escontext)
 | 
			
		||||
	uint64		tmp = 0;
 | 
			
		||||
	bool		neg = false;
 | 
			
		||||
	unsigned char digit;
 | 
			
		||||
	int64		result;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * The majority of cases are likely to be base-10 digits without any
 | 
			
		||||
@@ -714,10 +714,9 @@ pg_strtoint64_safe(const char *s, Node *escontext)
 | 
			
		||||
 | 
			
		||||
	if (neg)
 | 
			
		||||
	{
 | 
			
		||||
		/* check the negative equivalent will fit without overflowing */
 | 
			
		||||
		if (unlikely(tmp > (uint64) (-(PG_INT64_MIN + 1)) + 1))
 | 
			
		||||
		if (unlikely(pg_neg_u64_overflow(tmp, &result)))
 | 
			
		||||
			goto out_of_range;
 | 
			
		||||
		return -((int64) tmp);
 | 
			
		||||
		return result;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (unlikely(tmp > PG_INT64_MAX))
 | 
			
		||||
@@ -857,10 +856,9 @@ slow:
 | 
			
		||||
 | 
			
		||||
	if (neg)
 | 
			
		||||
	{
 | 
			
		||||
		/* check the negative equivalent will fit without overflowing */
 | 
			
		||||
		if (tmp > (uint64) (-(PG_INT64_MIN + 1)) + 1)
 | 
			
		||||
		if (unlikely(pg_neg_u64_overflow(tmp, &result)))
 | 
			
		||||
			goto out_of_range;
 | 
			
		||||
		return -((int64) tmp);
 | 
			
		||||
		return result;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (tmp > PG_INT64_MAX)
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user