Use new overflow aware integer operations.

A previous commit added inline functions that provide fast(er) and
correct overflow checks for signed integer math. Use them in a
significant portion of backend code.  There's more to touch in both
backend and frontend code, but these were the easily identifiable
cases.

The old overflow checks are noticeable in integer heavy workloads.

A secondary benefit is that getting rid of overflow checks that rely
on signed integer overflow wrapping around, will allow us to get rid
of -fwrapv in the future. Which in turn slows down other code.

Author: Andres Freund
Discussion: https://postgr.es/m/20171024103954.ztmatprlglz3rwke@alap3.anarazel.de
This commit is contained in:
Andres Freund 2017-12-12 16:32:31 -08:00
parent 4d6ad31257
commit 101c7ee3ee
14 changed files with 220 additions and 542 deletions

View File

@ -5,6 +5,7 @@
#include "btree_gist.h"
#include "btree_utils_num.h"
#include "common/int.h"
#include "utils/cash.h"
typedef struct
@ -99,15 +100,14 @@ cash_dist(PG_FUNCTION_ARGS)
Cash r;
Cash ra;
r = a - b;
ra = Abs(r);
/* Overflow check. */
if (ra < 0 || (!SAMESIGN(a, b) && !SAMESIGN(r, a)))
if (pg_sub_s64_overflow(a, b, &r) ||
r == INT64_MIN)
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("money out of range")));
ra = Abs(r);
PG_RETURN_CASH(ra);
}

View File

@ -5,6 +5,7 @@
#include "btree_gist.h"
#include "btree_utils_num.h"
#include "common/int.h"
typedef struct int16key
{
@ -98,15 +99,14 @@ int2_dist(PG_FUNCTION_ARGS)
int16 r;
int16 ra;
r = a - b;
ra = Abs(r);
/* Overflow check. */
if (ra < 0 || (!SAMESIGN(a, b) && !SAMESIGN(r, a)))
if (pg_sub_s16_overflow(a, b, &r) ||
r == INT16_MIN)
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("smallint out of range")));
ra = Abs(r);
PG_RETURN_INT16(ra);
}

View File

@ -5,6 +5,7 @@
#include "btree_gist.h"
#include "btree_utils_num.h"
#include "common/int.h"
typedef struct int32key
{
@ -99,15 +100,14 @@ int4_dist(PG_FUNCTION_ARGS)
int32 r;
int32 ra;
r = a - b;
ra = Abs(r);
/* Overflow check. */
if (ra < 0 || (!SAMESIGN(a, b) && !SAMESIGN(r, a)))
if (pg_sub_s32_overflow(a, b, &r) ||
r == INT32_MIN)
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer out of range")));
ra = Abs(r);
PG_RETURN_INT32(ra);
}

View File

@ -5,6 +5,7 @@
#include "btree_gist.h"
#include "btree_utils_num.h"
#include "common/int.h"
typedef struct int64key
{
@ -99,15 +100,14 @@ int8_dist(PG_FUNCTION_ARGS)
int64 r;
int64 ra;
r = a - b;
ra = Abs(r);
/* Overflow check. */
if (ra < 0 || (!SAMESIGN(a, b) && !SAMESIGN(r, a)))
if (pg_sub_s64_overflow(a, b, &r) ||
r == INT64_MIN)
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("bigint out of range")));
ra = Abs(r);
PG_RETURN_INT64(ra);
}

View File

@ -89,8 +89,6 @@ typedef struct
#define GET_FLOAT_DISTANCE(t, arg1, arg2) Abs( ((float8) *((const t *) (arg1))) - ((float8) *((const t *) (arg2))) )
#define SAMESIGN(a,b) (((a) < 0) == ((b) < 0))
/*
* check to see if a float4/8 val has underflowed or overflowed
* borrowed from src/backend/utils/adt/float.c

View File

@ -13,6 +13,7 @@
#include "postgres.h"
#include "catalog/pg_type.h"
#include "common/int.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
@ -118,15 +119,11 @@ array_append(PG_FUNCTION_ARGS)
if (eah->ndims == 1)
{
/* append newelem */
int ub;
lb = eah->lbound;
dimv = eah->dims;
ub = dimv[0] + lb[0] - 1;
indx = ub + 1;
/* overflow? */
if (indx < ub)
/* index of added elem is at lb[0] + (dimv[0] - 1) + 1 */
if (pg_add_s32_overflow(lb[0], dimv[0], &indx))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer out of range")));
@ -176,11 +173,9 @@ array_prepend(PG_FUNCTION_ARGS)
{
/* prepend newelem */
lb = eah->lbound;
indx = lb[0] - 1;
lb0 = lb[0];
/* overflow? */
if (indx > lb[0])
if (pg_sub_s32_overflow(lb0, 1, &indx))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer out of range")));

View File

@ -22,6 +22,7 @@
#include <ctype.h>
#include <math.h>
#include "common/int.h"
#include "libpq/pqformat.h"
#include "utils/builtins.h"
#include "utils/cash.h"
@ -199,20 +200,21 @@ cash_in(PG_FUNCTION_ARGS)
for (; *s; s++)
{
/* we look for digits as long as we have found less */
/* than the required number of decimal places */
/*
* We look for digits as long as we have found less than the required
* number of decimal places.
*/
if (isdigit((unsigned char) *s) && (!seen_dot || dec < fpoint))
{
Cash newvalue = (value * 10) - (*s - '0');
int8 digit = *s - '0';
if (newvalue / 10 != value)
if (pg_mul_s64_overflow(value, 10, &value) ||
pg_sub_s64_overflow(value, digit, &value))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("value \"%s\" is out of range for type %s",
str, "money")));
value = newvalue;
if (seen_dot)
dec++;
}
@ -230,26 +232,23 @@ cash_in(PG_FUNCTION_ARGS)
/* round off if there's another digit */
if (isdigit((unsigned char) *s) && *s >= '5')
value--; /* remember we build the value in the negative */
if (value > 0)
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("value \"%s\" is out of range for type %s",
str, "money")));
/* adjust for less than required decimal places */
for (; dec < fpoint; dec++)
{
Cash newvalue = value * 10;
if (newvalue / 10 != value)
/* remember we build the value in the negative */
if (pg_sub_s64_overflow(value, 1, &value))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("value \"%s\" is out of range for type %s",
str, "money")));
}
value = newvalue;
/* adjust for less than required decimal places */
for (; dec < fpoint; dec++)
{
if (pg_mul_s64_overflow(value, 10, &value))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("value \"%s\" is out of range for type %s",
str, "money")));
}
/*
@ -285,12 +284,12 @@ cash_in(PG_FUNCTION_ARGS)
*/
if (sgn > 0)
{
result = -value;
if (result < 0)
if (value == PG_INT64_MIN)
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("value \"%s\" is out of range for type %s",
str, "money")));
result = -value;
}
else
result = value;

View File

@ -20,6 +20,7 @@
#include <limits.h>
#include "catalog/pg_type.h"
#include "common/int.h"
#include "libpq/pqformat.h"
#include "utils/array.h"
#include "utils/builtins.h"
@ -3548,9 +3549,7 @@ width_bucket_float8(PG_FUNCTION_ARGS)
result = 0;
else if (operand >= bound2)
{
result = count + 1;
/* check for overflow */
if (result < count)
if (pg_add_s32_overflow(count, 1, &result))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer out of range")));
@ -3564,9 +3563,7 @@ width_bucket_float8(PG_FUNCTION_ARGS)
result = 0;
else if (operand <= bound2)
{
result = count + 1;
/* check for overflow */
if (result < count)
if (pg_add_s32_overflow(count, 1, &result))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer out of range")));

View File

@ -32,14 +32,12 @@
#include <limits.h>
#include "catalog/pg_type.h"
#include "common/int.h"
#include "funcapi.h"
#include "libpq/pqformat.h"
#include "utils/array.h"
#include "utils/builtins.h"
#define SAMESIGN(a,b) (((a) < 0) == ((b) < 0))
#define Int2VectorSize(n) (offsetof(int2vector, values) + (n) * sizeof(int16))
typedef struct
@ -328,7 +326,7 @@ i4toi2(PG_FUNCTION_ARGS)
{
int32 arg1 = PG_GETARG_INT32(0);
if (arg1 < SHRT_MIN || arg1 > SHRT_MAX)
if (unlikely(arg1 < SHRT_MIN) || unlikely(arg1 > SHRT_MAX))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("smallint out of range")));
@ -598,15 +596,12 @@ Datum
int4um(PG_FUNCTION_ARGS)
{
int32 arg = PG_GETARG_INT32(0);
int32 result;
result = -arg;
/* overflow check (needed for INT_MIN) */
if (arg != 0 && SAMESIGN(result, arg))
if (unlikely(arg == PG_INT32_MIN))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer out of range")));
PG_RETURN_INT32(result);
PG_RETURN_INT32(-arg);
}
Datum
@ -624,14 +619,7 @@ int4pl(PG_FUNCTION_ARGS)
int32 arg2 = PG_GETARG_INT32(1);
int32 result;
result = arg1 + arg2;
/*
* Overflow check. If the inputs are of different signs then their sum
* cannot overflow. If the inputs are of the same sign, their sum had
* better be that sign too.
*/
if (SAMESIGN(arg1, arg2) && !SAMESIGN(result, arg1))
if (unlikely(pg_add_s32_overflow(arg1, arg2, &result)))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer out of range")));
@ -645,14 +633,7 @@ int4mi(PG_FUNCTION_ARGS)
int32 arg2 = PG_GETARG_INT32(1);
int32 result;
result = arg1 - arg2;
/*
* Overflow check. If the inputs are of the same sign then their
* difference cannot overflow. If they are of different signs then the
* result should be of the same sign as the first input.
*/
if (!SAMESIGN(arg1, arg2) && !SAMESIGN(result, arg1))
if (unlikely(pg_sub_s32_overflow(arg1, arg2, &result)))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer out of range")));
@ -666,24 +647,7 @@ int4mul(PG_FUNCTION_ARGS)
int32 arg2 = PG_GETARG_INT32(1);
int32 result;
result = arg1 * arg2;
/*
* Overflow check. We basically check to see if result / arg2 gives arg1
* again. There are two cases where this fails: arg2 = 0 (which cannot
* overflow) and arg1 = INT_MIN, arg2 = -1 (where the division itself will
* overflow and thus incorrectly match).
*
* Since the division is likely much more expensive than the actual
* multiplication, we'd like to skip it where possible. The best bang for
* the buck seems to be to check whether both inputs are in the int16
* range; if so, no overflow is possible.
*/
if (!(arg1 >= (int32) SHRT_MIN && arg1 <= (int32) SHRT_MAX &&
arg2 >= (int32) SHRT_MIN && arg2 <= (int32) SHRT_MAX) &&
arg2 != 0 &&
((arg2 == -1 && arg1 < 0 && result < 0) ||
result / arg2 != arg1))
if (unlikely(pg_mul_s32_overflow(arg1, arg2, &result)))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer out of range")));
@ -714,12 +678,11 @@ int4div(PG_FUNCTION_ARGS)
*/
if (arg2 == -1)
{
result = -arg1;
/* overflow check (needed for INT_MIN) */
if (arg1 != 0 && SAMESIGN(result, arg1))
if (unlikely(arg1 == PG_INT32_MIN))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer out of range")));
result = -arg1;
PG_RETURN_INT32(result);
}
@ -736,9 +699,7 @@ int4inc(PG_FUNCTION_ARGS)
int32 arg = PG_GETARG_INT32(0);
int32 result;
result = arg + 1;
/* Overflow check */
if (arg > 0 && result < 0)
if (unlikely(pg_add_s32_overflow(arg, 1, &result)))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer out of range")));
@ -750,15 +711,12 @@ Datum
int2um(PG_FUNCTION_ARGS)
{
int16 arg = PG_GETARG_INT16(0);
int16 result;
result = -arg;
/* overflow check (needed for SHRT_MIN) */
if (arg != 0 && SAMESIGN(result, arg))
if (unlikely(arg == PG_INT16_MIN))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("smallint out of range")));
PG_RETURN_INT16(result);
PG_RETURN_INT16(-arg);
}
Datum
@ -776,14 +734,7 @@ int2pl(PG_FUNCTION_ARGS)
int16 arg2 = PG_GETARG_INT16(1);
int16 result;
result = arg1 + arg2;
/*
* Overflow check. If the inputs are of different signs then their sum
* cannot overflow. If the inputs are of the same sign, their sum had
* better be that sign too.
*/
if (SAMESIGN(arg1, arg2) && !SAMESIGN(result, arg1))
if (unlikely(pg_add_s16_overflow(arg1, arg2, &result)))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("smallint out of range")));
@ -797,14 +748,7 @@ int2mi(PG_FUNCTION_ARGS)
int16 arg2 = PG_GETARG_INT16(1);
int16 result;
result = arg1 - arg2;
/*
* Overflow check. If the inputs are of the same sign then their
* difference cannot overflow. If they are of different signs then the
* result should be of the same sign as the first input.
*/
if (!SAMESIGN(arg1, arg2) && !SAMESIGN(result, arg1))
if (unlikely(pg_sub_s16_overflow(arg1, arg2, &result)))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("smallint out of range")));
@ -816,20 +760,14 @@ int2mul(PG_FUNCTION_ARGS)
{
int16 arg1 = PG_GETARG_INT16(0);
int16 arg2 = PG_GETARG_INT16(1);
int32 result32;
int16 result;
/*
* The most practical way to detect overflow is to do the arithmetic in
* int32 (so that the result can't overflow) and then do a range check.
*/
result32 = (int32) arg1 * (int32) arg2;
if (result32 < SHRT_MIN || result32 > SHRT_MAX)
if (unlikely(pg_mul_s16_overflow(arg1, arg2, &result)))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("smallint out of range")));
PG_RETURN_INT16((int16) result32);
PG_RETURN_INT16(result);
}
Datum
@ -856,12 +794,11 @@ int2div(PG_FUNCTION_ARGS)
*/
if (arg2 == -1)
{
result = -arg1;
/* overflow check (needed for SHRT_MIN) */
if (arg1 != 0 && SAMESIGN(result, arg1))
if (unlikely(arg1 == INT16_MIN))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("smallint out of range")));
result = -arg1;
PG_RETURN_INT16(result);
}
@ -879,14 +816,7 @@ int24pl(PG_FUNCTION_ARGS)
int32 arg2 = PG_GETARG_INT32(1);
int32 result;
result = arg1 + arg2;
/*
* Overflow check. If the inputs are of different signs then their sum
* cannot overflow. If the inputs are of the same sign, their sum had
* better be that sign too.
*/
if (SAMESIGN(arg1, arg2) && !SAMESIGN(result, arg1))
if (unlikely(pg_add_s32_overflow((int32) arg1, arg2, &result)))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer out of range")));
@ -900,14 +830,7 @@ int24mi(PG_FUNCTION_ARGS)
int32 arg2 = PG_GETARG_INT32(1);
int32 result;
result = arg1 - arg2;
/*
* Overflow check. If the inputs are of the same sign then their
* difference cannot overflow. If they are of different signs then the
* result should be of the same sign as the first input.
*/
if (!SAMESIGN(arg1, arg2) && !SAMESIGN(result, arg1))
if (unlikely(pg_sub_s32_overflow((int32) arg1, arg2, &result)))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer out of range")));
@ -921,20 +844,7 @@ int24mul(PG_FUNCTION_ARGS)
int32 arg2 = PG_GETARG_INT32(1);
int32 result;
result = arg1 * arg2;
/*
* Overflow check. We basically check to see if result / arg2 gives arg1
* again. There is one case where this fails: arg2 = 0 (which cannot
* overflow).
*
* Since the division is likely much more expensive than the actual
* multiplication, we'd like to skip it where possible. The best bang for
* the buck seems to be to check whether both inputs are in the int16
* range; if so, no overflow is possible.
*/
if (!(arg2 >= (int32) SHRT_MIN && arg2 <= (int32) SHRT_MAX) &&
result / arg2 != arg1)
if (unlikely(pg_mul_s32_overflow((int32) arg1, arg2, &result)))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer out of range")));
@ -947,7 +857,7 @@ int24div(PG_FUNCTION_ARGS)
int16 arg1 = PG_GETARG_INT16(0);
int32 arg2 = PG_GETARG_INT32(1);
if (arg2 == 0)
if (unlikely(arg2 == 0))
{
ereport(ERROR,
(errcode(ERRCODE_DIVISION_BY_ZERO),
@ -967,14 +877,7 @@ int42pl(PG_FUNCTION_ARGS)
int16 arg2 = PG_GETARG_INT16(1);
int32 result;
result = arg1 + arg2;
/*
* Overflow check. If the inputs are of different signs then their sum
* cannot overflow. If the inputs are of the same sign, their sum had
* better be that sign too.
*/
if (SAMESIGN(arg1, arg2) && !SAMESIGN(result, arg1))
if (unlikely(pg_add_s32_overflow(arg1, (int32) arg2, &result)))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer out of range")));
@ -988,14 +891,7 @@ int42mi(PG_FUNCTION_ARGS)
int16 arg2 = PG_GETARG_INT16(1);
int32 result;
result = arg1 - arg2;
/*
* Overflow check. If the inputs are of the same sign then their
* difference cannot overflow. If they are of different signs then the
* result should be of the same sign as the first input.
*/
if (!SAMESIGN(arg1, arg2) && !SAMESIGN(result, arg1))
if (unlikely(pg_sub_s32_overflow(arg1, (int32) arg2, &result)))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer out of range")));
@ -1009,20 +905,7 @@ int42mul(PG_FUNCTION_ARGS)
int16 arg2 = PG_GETARG_INT16(1);
int32 result;
result = arg1 * arg2;
/*
* Overflow check. We basically check to see if result / arg1 gives arg2
* again. There is one case where this fails: arg1 = 0 (which cannot
* overflow).
*
* Since the division is likely much more expensive than the actual
* multiplication, we'd like to skip it where possible. The best bang for
* the buck seems to be to check whether both inputs are in the int16
* range; if so, no overflow is possible.
*/
if (!(arg1 >= (int32) SHRT_MIN && arg1 <= (int32) SHRT_MAX) &&
result / arg1 != arg2)
if (unlikely(pg_mul_s32_overflow(arg1, (int32) arg2, &result)))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer out of range")));
@ -1036,7 +919,7 @@ int42div(PG_FUNCTION_ARGS)
int16 arg2 = PG_GETARG_INT16(1);
int32 result;
if (arg2 == 0)
if (unlikely(arg2 == 0))
{
ereport(ERROR,
(errcode(ERRCODE_DIVISION_BY_ZERO),
@ -1053,12 +936,11 @@ int42div(PG_FUNCTION_ARGS)
*/
if (arg2 == -1)
{
result = -arg1;
/* overflow check (needed for INT_MIN) */
if (arg1 != 0 && SAMESIGN(result, arg1))
if (unlikely(arg1 == PG_INT32_MIN))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer out of range")));
result = -arg1;
PG_RETURN_INT32(result);
}
@ -1075,7 +957,7 @@ int4mod(PG_FUNCTION_ARGS)
int32 arg1 = PG_GETARG_INT32(0);
int32 arg2 = PG_GETARG_INT32(1);
if (arg2 == 0)
if (unlikely(arg2 == 0))
{
ereport(ERROR,
(errcode(ERRCODE_DIVISION_BY_ZERO),
@ -1103,7 +985,7 @@ int2mod(PG_FUNCTION_ARGS)
int16 arg1 = PG_GETARG_INT16(0);
int16 arg2 = PG_GETARG_INT16(1);
if (arg2 == 0)
if (unlikely(arg2 == 0))
{
ereport(ERROR,
(errcode(ERRCODE_DIVISION_BY_ZERO),
@ -1136,12 +1018,11 @@ int4abs(PG_FUNCTION_ARGS)
int32 arg1 = PG_GETARG_INT32(0);
int32 result;
result = (arg1 < 0) ? -arg1 : arg1;
/* overflow check (needed for INT_MIN) */
if (result < 0)
if (unlikely(arg1 == INT32_MIN))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer out of range")));
result = (arg1 < 0) ? -arg1 : arg1;
PG_RETURN_INT32(result);
}
@ -1151,12 +1032,11 @@ int2abs(PG_FUNCTION_ARGS)
int16 arg1 = PG_GETARG_INT16(0);
int16 result;
result = (arg1 < 0) ? -arg1 : arg1;
/* overflow check (needed for SHRT_MIN) */
if (result < 0)
if (unlikely(arg1 == INT16_MIN))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("smallint out of range")));
result = (arg1 < 0) ? -arg1 : arg1;
PG_RETURN_INT16(result);
}
@ -1381,11 +1261,11 @@ generate_series_step_int4(PG_FUNCTION_ARGS)
if ((fctx->step > 0 && fctx->current <= fctx->finish) ||
(fctx->step < 0 && fctx->current >= fctx->finish))
{
/* increment current in preparation for next iteration */
fctx->current += fctx->step;
/* if next-value computation overflows, this is the final result */
if (SAMESIGN(result, fctx->step) && !SAMESIGN(result, fctx->current))
/*
* Increment current in preparation for next iteration. If next-value
* computation overflows, this is the final result.
*/
if (pg_add_s32_overflow(fctx->current, fctx->step, &fctx->current))
fctx->step = 0;
/* do when there is more left to send */

View File

@ -17,6 +17,7 @@
#include <limits.h>
#include <math.h>
#include "common/int.h"
#include "funcapi.h"
#include "libpq/pqformat.h"
#include "utils/int8.h"
@ -25,8 +26,6 @@
#define MAXINT8LEN 25
#define SAMESIGN(a,b) (((a) < 0) == ((b) < 0))
typedef struct
{
int64 current;
@ -56,11 +55,14 @@ scanint8(const char *str, bool errorOK, int64 *result)
{
const char *ptr = str;
int64 tmp = 0;
int sign = 1;
bool neg = false;
/*
* Do our own scan, rather than relying on sscanf which might be broken
* for long long.
*
* As INT64_MIN can't be stored as a positive 64 bit integer, accumulate
* value as a negative number.
*/
/* skip leading spaces */
@ -71,72 +73,60 @@ scanint8(const char *str, bool errorOK, int64 *result)
if (*ptr == '-')
{
ptr++;
/*
* Do an explicit check for INT64_MIN. Ugly though this is, it's
* cleaner than trying to get the loop below to handle it portably.
*/
if (strncmp(ptr, "9223372036854775808", 19) == 0)
{
tmp = PG_INT64_MIN;
ptr += 19;
goto gotdigits;
}
sign = -1;
neg = true;
}
else if (*ptr == '+')
ptr++;
/* require at least one digit */
if (!isdigit((unsigned char) *ptr))
if (unlikely(!isdigit((unsigned char) *ptr)))
{
if (errorOK)
return false;
else
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for integer: \"%s\"",
str)));
goto invalid_syntax;
}
/* process digits */
while (*ptr && isdigit((unsigned char) *ptr))
{
int64 newtmp = tmp * 10 + (*ptr++ - '0');
int8 digit = (*ptr++ - '0');
if ((newtmp / 10) != tmp) /* overflow? */
{
if (errorOK)
return false;
else
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("value \"%s\" is out of range for type %s",
str, "bigint")));
}
tmp = newtmp;
if (unlikely(pg_mul_s64_overflow(tmp, 10, &tmp)) ||
unlikely(pg_sub_s64_overflow(tmp, digit, &tmp)))
goto out_of_range;
}
gotdigits:
/* allow trailing whitespace, but not other trailing chars */
while (*ptr != '\0' && isspace((unsigned char) *ptr))
ptr++;
if (*ptr != '\0')
{
if (errorOK)
return false;
else
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for integer: \"%s\"",
str)));
}
if (unlikely(*ptr != '\0'))
goto invalid_syntax;
*result = (sign < 0) ? -tmp : tmp;
if (!neg)
{
if (unlikely(tmp == INT64_MIN))
goto out_of_range;
tmp = -tmp;
}
*result = tmp;
return true;
out_of_range:
if (errorOK)
return false;
else
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("value \"%s\" is out of range for type %s",
str, "bigint")));
invalid_syntax:
if (errorOK)
return false;
else
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for integer: \"%s\"",
str)));
}
/* int8in()
@ -492,12 +482,11 @@ int8um(PG_FUNCTION_ARGS)
int64 arg = PG_GETARG_INT64(0);
int64 result;
result = -arg;
/* overflow check (needed for INT64_MIN) */
if (arg != 0 && SAMESIGN(result, arg))
if (unlikely(arg == PG_INT64_MIN))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("bigint out of range")));
result = -arg;
PG_RETURN_INT64(result);
}
@ -516,14 +505,7 @@ int8pl(PG_FUNCTION_ARGS)
int64 arg2 = PG_GETARG_INT64(1);
int64 result;
result = arg1 + arg2;
/*
* Overflow check. If the inputs are of different signs then their sum
* cannot overflow. If the inputs are of the same sign, their sum had
* better be that sign too.
*/
if (SAMESIGN(arg1, arg2) && !SAMESIGN(result, arg1))
if (unlikely(pg_add_s64_overflow(arg1, arg2, &result)))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("bigint out of range")));
@ -537,14 +519,7 @@ int8mi(PG_FUNCTION_ARGS)
int64 arg2 = PG_GETARG_INT64(1);
int64 result;
result = arg1 - arg2;
/*
* Overflow check. If the inputs are of the same sign then their
* difference cannot overflow. If they are of different signs then the
* result should be of the same sign as the first input.
*/
if (!SAMESIGN(arg1, arg2) && !SAMESIGN(result, arg1))
if (unlikely(pg_sub_s64_overflow(arg1, arg2, &result)))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("bigint out of range")));
@ -558,28 +533,10 @@ int8mul(PG_FUNCTION_ARGS)
int64 arg2 = PG_GETARG_INT64(1);
int64 result;
result = arg1 * arg2;
/*
* Overflow check. We basically check to see if result / arg2 gives arg1
* again. There are two cases where this fails: arg2 = 0 (which cannot
* overflow) and arg1 = INT64_MIN, arg2 = -1 (where the division itself
* will overflow and thus incorrectly match).
*
* Since the division is likely much more expensive than the actual
* multiplication, we'd like to skip it where possible. The best bang for
* the buck seems to be to check whether both inputs are in the int32
* range; if so, no overflow is possible.
*/
if (arg1 != (int64) ((int32) arg1) || arg2 != (int64) ((int32) arg2))
{
if (arg2 != 0 &&
((arg2 == -1 && arg1 < 0 && result < 0) ||
result / arg2 != arg1))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("bigint out of range")));
}
if (unlikely(pg_mul_s64_overflow(arg1, arg2, &result)))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("bigint out of range")));
PG_RETURN_INT64(result);
}
@ -607,12 +564,11 @@ int8div(PG_FUNCTION_ARGS)
*/
if (arg2 == -1)
{
result = -arg1;
/* overflow check (needed for INT64_MIN) */
if (arg1 != 0 && SAMESIGN(result, arg1))
if (unlikely(arg1 == INT64_MIN))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("bigint out of range")));
result = -arg1;
PG_RETURN_INT64(result);
}
@ -632,12 +588,11 @@ int8abs(PG_FUNCTION_ARGS)
int64 arg1 = PG_GETARG_INT64(0);
int64 result;
result = (arg1 < 0) ? -arg1 : arg1;
/* overflow check (needed for INT64_MIN) */
if (result < 0)
if (unlikely(arg1 == INT64_MIN))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("bigint out of range")));
result = (arg1 < 0) ? -arg1 : arg1;
PG_RETURN_INT64(result);
}
@ -650,7 +605,7 @@ int8mod(PG_FUNCTION_ARGS)
int64 arg1 = PG_GETARG_INT64(0);
int64 arg2 = PG_GETARG_INT64(1);
if (arg2 == 0)
if (unlikely(arg2 == 0))
{
ereport(ERROR,
(errcode(ERRCODE_DIVISION_BY_ZERO),
@ -687,16 +642,12 @@ int8inc(PG_FUNCTION_ARGS)
if (AggCheckCallContext(fcinfo, NULL))
{
int64 *arg = (int64 *) PG_GETARG_POINTER(0);
int64 result;
result = *arg + 1;
/* Overflow check */
if (result < 0 && *arg > 0)
if (unlikely(pg_add_s64_overflow(*arg, 1, arg)))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("bigint out of range")));
*arg = result;
PG_RETURN_POINTER(arg);
}
else
@ -706,9 +657,7 @@ int8inc(PG_FUNCTION_ARGS)
int64 arg = PG_GETARG_INT64(0);
int64 result;
result = arg + 1;
/* Overflow check */
if (result < 0 && arg > 0)
if (unlikely(pg_add_s64_overflow(arg, 1, &result)))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("bigint out of range")));
@ -731,16 +680,11 @@ int8dec(PG_FUNCTION_ARGS)
if (AggCheckCallContext(fcinfo, NULL))
{
int64 *arg = (int64 *) PG_GETARG_POINTER(0);
int64 result;
result = *arg - 1;
/* Overflow check */
if (result > 0 && *arg < 0)
if (unlikely(pg_sub_s64_overflow(*arg, 1, arg)))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("bigint out of range")));
*arg = result;
PG_RETURN_POINTER(arg);
}
else
@ -750,9 +694,7 @@ int8dec(PG_FUNCTION_ARGS)
int64 arg = PG_GETARG_INT64(0);
int64 result;
result = arg - 1;
/* Overflow check */
if (result > 0 && arg < 0)
if (unlikely(pg_sub_s64_overflow(arg, 1, &result)))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("bigint out of range")));
@ -821,14 +763,7 @@ int84pl(PG_FUNCTION_ARGS)
int32 arg2 = PG_GETARG_INT32(1);
int64 result;
result = arg1 + arg2;
/*
* Overflow check. If the inputs are of different signs then their sum
* cannot overflow. If the inputs are of the same sign, their sum had
* better be that sign too.
*/
if (SAMESIGN(arg1, arg2) && !SAMESIGN(result, arg1))
if (unlikely(pg_add_s64_overflow(arg1, (int64) arg2, &result)))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("bigint out of range")));
@ -842,14 +777,7 @@ int84mi(PG_FUNCTION_ARGS)
int32 arg2 = PG_GETARG_INT32(1);
int64 result;
result = arg1 - arg2;
/*
* Overflow check. If the inputs are of the same sign then their
* difference cannot overflow. If they are of different signs then the
* result should be of the same sign as the first input.
*/
if (!SAMESIGN(arg1, arg2) && !SAMESIGN(result, arg1))
if (unlikely(pg_sub_s64_overflow(arg1, (int64) arg2, &result)))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("bigint out of range")));
@ -863,20 +791,7 @@ int84mul(PG_FUNCTION_ARGS)
int32 arg2 = PG_GETARG_INT32(1);
int64 result;
result = arg1 * arg2;
/*
* Overflow check. We basically check to see if result / arg1 gives arg2
* again. There is one case where this fails: arg1 = 0 (which cannot
* overflow).
*
* Since the division is likely much more expensive than the actual
* multiplication, we'd like to skip it where possible. The best bang for
* the buck seems to be to check whether both inputs are in the int32
* range; if so, no overflow is possible.
*/
if (arg1 != (int64) ((int32) arg1) &&
result / arg1 != arg2)
if (unlikely(pg_mul_s64_overflow(arg1, (int64) arg2, &result)))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("bigint out of range")));
@ -907,12 +822,11 @@ int84div(PG_FUNCTION_ARGS)
*/
if (arg2 == -1)
{
result = -arg1;
/* overflow check (needed for INT64_MIN) */
if (arg1 != 0 && SAMESIGN(result, arg1))
if (unlikely(arg1 == INT64_MIN))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("bigint out of range")));
result = -arg1;
PG_RETURN_INT64(result);
}
@ -930,14 +844,7 @@ int48pl(PG_FUNCTION_ARGS)
int64 arg2 = PG_GETARG_INT64(1);
int64 result;
result = arg1 + arg2;
/*
* Overflow check. If the inputs are of different signs then their sum
* cannot overflow. If the inputs are of the same sign, their sum had
* better be that sign too.
*/
if (SAMESIGN(arg1, arg2) && !SAMESIGN(result, arg1))
if (unlikely(pg_add_s64_overflow((int64) arg1, arg2, &result)))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("bigint out of range")));
@ -951,14 +858,7 @@ int48mi(PG_FUNCTION_ARGS)
int64 arg2 = PG_GETARG_INT64(1);
int64 result;
result = arg1 - arg2;
/*
* Overflow check. If the inputs are of the same sign then their
* difference cannot overflow. If they are of different signs then the
* result should be of the same sign as the first input.
*/
if (!SAMESIGN(arg1, arg2) && !SAMESIGN(result, arg1))
if (unlikely(pg_sub_s64_overflow((int64) arg1, arg2, &result)))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("bigint out of range")));
@ -972,20 +872,7 @@ int48mul(PG_FUNCTION_ARGS)
int64 arg2 = PG_GETARG_INT64(1);
int64 result;
result = arg1 * arg2;
/*
* Overflow check. We basically check to see if result / arg2 gives arg1
* again. There is one case where this fails: arg2 = 0 (which cannot
* overflow).
*
* Since the division is likely much more expensive than the actual
* multiplication, we'd like to skip it where possible. The best bang for
* the buck seems to be to check whether both inputs are in the int32
* range; if so, no overflow is possible.
*/
if (arg2 != (int64) ((int32) arg2) &&
result / arg2 != arg1)
if (unlikely(pg_mul_s64_overflow((int64) arg1, arg2, &result)))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("bigint out of range")));
@ -998,7 +885,7 @@ int48div(PG_FUNCTION_ARGS)
int32 arg1 = PG_GETARG_INT32(0);
int64 arg2 = PG_GETARG_INT64(1);
if (arg2 == 0)
if (unlikely(arg2 == 0))
{
ereport(ERROR,
(errcode(ERRCODE_DIVISION_BY_ZERO),
@ -1018,14 +905,7 @@ int82pl(PG_FUNCTION_ARGS)
int16 arg2 = PG_GETARG_INT16(1);
int64 result;
result = arg1 + arg2;
/*
* Overflow check. If the inputs are of different signs then their sum
* cannot overflow. If the inputs are of the same sign, their sum had
* better be that sign too.
*/
if (SAMESIGN(arg1, arg2) && !SAMESIGN(result, arg1))
if (unlikely(pg_add_s64_overflow(arg1, (int64) arg2, &result)))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("bigint out of range")));
@ -1039,14 +919,7 @@ int82mi(PG_FUNCTION_ARGS)
int16 arg2 = PG_GETARG_INT16(1);
int64 result;
result = arg1 - arg2;
/*
* Overflow check. If the inputs are of the same sign then their
* difference cannot overflow. If they are of different signs then the
* result should be of the same sign as the first input.
*/
if (!SAMESIGN(arg1, arg2) && !SAMESIGN(result, arg1))
if (unlikely(pg_sub_s64_overflow(arg1, (int64) arg2, &result)))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("bigint out of range")));
@ -1060,20 +933,7 @@ int82mul(PG_FUNCTION_ARGS)
int16 arg2 = PG_GETARG_INT16(1);
int64 result;
result = arg1 * arg2;
/*
* Overflow check. We basically check to see if result / arg1 gives arg2
* again. There is one case where this fails: arg1 = 0 (which cannot
* overflow).
*
* Since the division is likely much more expensive than the actual
* multiplication, we'd like to skip it where possible. The best bang for
* the buck seems to be to check whether both inputs are in the int32
* range; if so, no overflow is possible.
*/
if (arg1 != (int64) ((int32) arg1) &&
result / arg1 != arg2)
if (unlikely(pg_mul_s64_overflow(arg1, (int64) arg2, &result)))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("bigint out of range")));
@ -1087,7 +947,7 @@ int82div(PG_FUNCTION_ARGS)
int16 arg2 = PG_GETARG_INT16(1);
int64 result;
if (arg2 == 0)
if (unlikely(arg2 == 0))
{
ereport(ERROR,
(errcode(ERRCODE_DIVISION_BY_ZERO),
@ -1104,12 +964,11 @@ int82div(PG_FUNCTION_ARGS)
*/
if (arg2 == -1)
{
result = -arg1;
/* overflow check (needed for INT64_MIN) */
if (arg1 != 0 && SAMESIGN(result, arg1))
if (unlikely(arg1 == INT64_MIN))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("bigint out of range")));
result = -arg1;
PG_RETURN_INT64(result);
}
@ -1127,14 +986,7 @@ int28pl(PG_FUNCTION_ARGS)
int64 arg2 = PG_GETARG_INT64(1);
int64 result;
result = arg1 + arg2;
/*
* Overflow check. If the inputs are of different signs then their sum
* cannot overflow. If the inputs are of the same sign, their sum had
* better be that sign too.
*/
if (SAMESIGN(arg1, arg2) && !SAMESIGN(result, arg1))
if (unlikely(pg_add_s64_overflow((int64) arg1, arg2, &result)))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("bigint out of range")));
@ -1148,14 +1000,7 @@ int28mi(PG_FUNCTION_ARGS)
int64 arg2 = PG_GETARG_INT64(1);
int64 result;
result = arg1 - arg2;
/*
* Overflow check. If the inputs are of the same sign then their
* difference cannot overflow. If they are of different signs then the
* result should be of the same sign as the first input.
*/
if (!SAMESIGN(arg1, arg2) && !SAMESIGN(result, arg1))
if (unlikely(pg_sub_s64_overflow((int64) arg1, arg2, &result)))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("bigint out of range")));
@ -1169,20 +1014,7 @@ int28mul(PG_FUNCTION_ARGS)
int64 arg2 = PG_GETARG_INT64(1);
int64 result;
result = arg1 * arg2;
/*
* Overflow check. We basically check to see if result / arg2 gives arg1
* again. There is one case where this fails: arg2 = 0 (which cannot
* overflow).
*
* Since the division is likely much more expensive than the actual
* multiplication, we'd like to skip it where possible. The best bang for
* the buck seems to be to check whether both inputs are in the int32
* range; if so, no overflow is possible.
*/
if (arg2 != (int64) ((int32) arg2) &&
result / arg2 != arg1)
if (unlikely(pg_mul_s64_overflow((int64) arg1, arg2, &result)))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("bigint out of range")));
@ -1195,7 +1027,7 @@ int28div(PG_FUNCTION_ARGS)
int16 arg1 = PG_GETARG_INT16(0);
int64 arg2 = PG_GETARG_INT64(1);
if (arg2 == 0)
if (unlikely(arg2 == 0))
{
ereport(ERROR,
(errcode(ERRCODE_DIVISION_BY_ZERO),
@ -1287,17 +1119,13 @@ Datum
int84(PG_FUNCTION_ARGS)
{
int64 arg = PG_GETARG_INT64(0);
int32 result;
result = (int32) arg;
/* Test for overflow by reverse-conversion. */
if ((int64) result != arg)
if (unlikely(arg < PG_INT32_MIN) || unlikely(arg > PG_INT32_MAX))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer out of range")));
PG_RETURN_INT32(result);
PG_RETURN_INT32((int32) arg);
}
Datum
@ -1312,17 +1140,13 @@ Datum
int82(PG_FUNCTION_ARGS)
{
int64 arg = PG_GETARG_INT64(0);
int16 result;
result = (int16) arg;
/* Test for overflow by reverse-conversion. */
if ((int64) result != arg)
if (unlikely(arg < PG_INT16_MIN) || unlikely(arg > PG_INT16_MAX))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("smallint out of range")));
PG_RETURN_INT16(result);
PG_RETURN_INT16((int16) arg);
}
Datum
@ -1348,18 +1172,15 @@ dtoi8(PG_FUNCTION_ARGS)
/* Round arg to nearest integer (but it's still in float form) */
arg = rint(arg);
/*
* Does it fit in an int64? Avoid assuming that we have handy constants
* defined for the range boundaries, instead test for overflow by
* reverse-conversion.
*/
result = (int64) arg;
if ((float8) result != arg)
if (unlikely(arg < (double) PG_INT64_MIN) ||
unlikely(arg > (double) PG_INT64_MAX) ||
unlikely(isnan(arg)))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("bigint out of range")));
result = (int64) arg;
PG_RETURN_INT64(result);
}
@ -1381,42 +1202,32 @@ Datum
ftoi8(PG_FUNCTION_ARGS)
{
float4 arg = PG_GETARG_FLOAT4(0);
int64 result;
float8 darg;
/* Round arg to nearest integer (but it's still in float form) */
darg = rint(arg);
/*
* Does it fit in an int64? Avoid assuming that we have handy constants
* defined for the range boundaries, instead test for overflow by
* reverse-conversion.
*/
result = (int64) darg;
if ((float8) result != darg)
if (unlikely(arg < (float4) PG_INT64_MIN) ||
unlikely(arg > (float4) PG_INT64_MAX) ||
unlikely(isnan(arg)))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("bigint out of range")));
PG_RETURN_INT64(result);
PG_RETURN_INT64((int64) darg);
}
Datum
i8tooid(PG_FUNCTION_ARGS)
{
int64 arg = PG_GETARG_INT64(0);
Oid result;
result = (Oid) arg;
/* Test for overflow by reverse-conversion. */
if ((int64) result != arg)
if (unlikely(arg < 0) || unlikely(arg > PG_UINT32_MAX))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("OID out of range")));
PG_RETURN_OID(result);
PG_RETURN_OID((Oid) arg);
}
Datum
@ -1494,11 +1305,11 @@ generate_series_step_int8(PG_FUNCTION_ARGS)
if ((fctx->step > 0 && fctx->current <= fctx->finish) ||
(fctx->step < 0 && fctx->current >= fctx->finish))
{
/* increment current in preparation for next iteration */
fctx->current += fctx->step;
/* if next-value computation overflows, this is the final result */
if (SAMESIGN(result, fctx->step) && !SAMESIGN(result, fctx->current))
/*
* Increment current in preparation for next iteration. If next-value
* computation overflows, this is the final result.
*/
if (pg_add_s64_overflow(fctx->current, fctx->step, &fctx->current))
fctx->step = 0;
/* do when there is more left to send */

View File

@ -28,6 +28,7 @@
#include "access/hash.h"
#include "catalog/pg_type.h"
#include "common/int.h"
#include "funcapi.h"
#include "lib/hyperloglog.h"
#include "libpq/pqformat.h"
@ -6169,8 +6170,7 @@ numericvar_to_int64(const NumericVar *var, int64 *result)
int ndigits;
int weight;
int i;
int64 val,
oldval;
int64 val;
bool neg;
NumericVar rounded;
@ -6196,27 +6196,25 @@ numericvar_to_int64(const NumericVar *var, int64 *result)
weight = rounded.weight;
Assert(weight >= 0 && ndigits <= weight + 1);
/* Construct the result */
/*
* Construct the result. To avoid issues with converting a value
* corresponding to INT64_MIN (which can't be represented as a positive 64
* bit two's complement integer), accumulate value as a negative number.
*/
digits = rounded.digits;
neg = (rounded.sign == NUMERIC_NEG);
val = digits[0];
val = -digits[0];
for (i = 1; i <= weight; i++)
{
oldval = val;
val *= NBASE;
if (i < ndigits)
val += digits[i];
/*
* The overflow check is a bit tricky because we want to accept
* INT64_MIN, which will overflow the positive accumulator. We can
* detect this case easily though because INT64_MIN is the only
* nonzero value for which -val == val (on a two's complement machine,
* anyway).
*/
if ((val / NBASE) != oldval) /* possible overflow? */
if (unlikely(pg_mul_s64_overflow(val, NBASE, &val)))
{
if (!neg || (-val) != val || val == 0 || oldval < 0)
free_var(&rounded);
return false;
}
if (i < ndigits)
{
if (unlikely(pg_sub_s64_overflow(val, digits[i], &val)))
{
free_var(&rounded);
return false;
@ -6226,7 +6224,14 @@ numericvar_to_int64(const NumericVar *var, int64 *result)
free_var(&rounded);
*result = neg ? -val : val;
if (!neg)
{
if (unlikely(val == INT64_MIN))
return false;
val = -val;
}
*result = val;
return true;
}

View File

@ -15,6 +15,7 @@
*/
#include "postgres.h"
#include "common/int.h"
#include "utils/builtins.h"
#include "utils/formatting.h"
#include "mb/pg_wchar.h"
@ -1045,19 +1046,12 @@ repeat(PG_FUNCTION_ARGS)
count = 0;
slen = VARSIZE_ANY_EXHDR(string);
tlen = VARHDRSZ + (count * slen);
/* Check for integer overflow */
if (slen != 0 && count != 0)
{
int check = count * slen;
int check2 = check + VARHDRSZ;
if ((check / slen) != count || check2 <= check)
ereport(ERROR,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg("requested length too large")));
}
if (unlikely(pg_mul_s32_overflow(count, slen, &tlen)) ||
unlikely(pg_add_s32_overflow(tlen, VARHDRSZ, &tlen)))
ereport(ERROR,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg("requested length too large")));
result = (text *) palloc(tlen);

View File

@ -17,6 +17,7 @@
#include "postgres.h"
#include "access/htup_details.h"
#include "common/int.h"
#include "libpq/pqformat.h"
#include "nodes/nodeFuncs.h"
#include "utils/array.h"
@ -1166,8 +1167,7 @@ bit_overlay(VarBit *t1, VarBit *t2, int sp, int sl)
ereport(ERROR,
(errcode(ERRCODE_SUBSTRING_ERROR),
errmsg("negative substring length not allowed")));
sp_pl_sl = sp + sl;
if (sp_pl_sl <= sl)
if (pg_add_s32_overflow(sp, sl, &sp_pl_sl))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer out of range")));

View File

@ -21,6 +21,7 @@
#include "access/tuptoaster.h"
#include "catalog/pg_collation.h"
#include "catalog/pg_type.h"
#include "common/int.h"
#include "common/md5.h"
#include "lib/hyperloglog.h"
#include "libpq/pqformat.h"
@ -1047,8 +1048,7 @@ text_overlay(text *t1, text *t2, int sp, int sl)
ereport(ERROR,
(errcode(ERRCODE_SUBSTRING_ERROR),
errmsg("negative substring length not allowed")));
sp_pl_sl = sp + sl;
if (sp_pl_sl <= sl)
if (pg_add_s32_overflow(sp, sl, &sp_pl_sl))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer out of range")));
@ -2950,8 +2950,7 @@ bytea_overlay(bytea *t1, bytea *t2, int sp, int sl)
ereport(ERROR,
(errcode(ERRCODE_SUBSTRING_ERROR),
errmsg("negative substring length not allowed")));
sp_pl_sl = sp + sl;
if (sp_pl_sl <= sl)
if (pg_add_s32_overflow(sp, sl, &sp_pl_sl))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer out of range")));
@ -5279,13 +5278,13 @@ text_format_parse_digits(const char **ptr, const char *end_ptr, int *value)
while (*cp >= '0' && *cp <= '9')
{
int newval = val * 10 + (*cp - '0');
int8 digit = (*cp - '0');
if (newval / 10 != val) /* overflow? */
if (unlikely(pg_mul_s32_overflow(val, 10, &val)) ||
unlikely(pg_add_s32_overflow(val, digit, &val)))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("number is out of range")));
val = newval;
ADVANCE_PARSE_POINTER(cp, end_ptr);
found = true;
}