Commit 101c7ee3 authored by Andres Freund's avatar Andres Freund

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
parent 4d6ad312
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include "btree_gist.h" #include "btree_gist.h"
#include "btree_utils_num.h" #include "btree_utils_num.h"
#include "common/int.h"
#include "utils/cash.h" #include "utils/cash.h"
typedef struct typedef struct
...@@ -99,15 +100,14 @@ cash_dist(PG_FUNCTION_ARGS) ...@@ -99,15 +100,14 @@ cash_dist(PG_FUNCTION_ARGS)
Cash r; Cash r;
Cash ra; Cash ra;
r = a - b; if (pg_sub_s64_overflow(a, b, &r) ||
ra = Abs(r); r == INT64_MIN)
/* Overflow check. */
if (ra < 0 || (!SAMESIGN(a, b) && !SAMESIGN(r, a)))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("money out of range"))); errmsg("money out of range")));
ra = Abs(r);
PG_RETURN_CASH(ra); PG_RETURN_CASH(ra);
} }
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include "btree_gist.h" #include "btree_gist.h"
#include "btree_utils_num.h" #include "btree_utils_num.h"
#include "common/int.h"
typedef struct int16key typedef struct int16key
{ {
...@@ -98,15 +99,14 @@ int2_dist(PG_FUNCTION_ARGS) ...@@ -98,15 +99,14 @@ int2_dist(PG_FUNCTION_ARGS)
int16 r; int16 r;
int16 ra; int16 ra;
r = a - b; if (pg_sub_s16_overflow(a, b, &r) ||
ra = Abs(r); r == INT16_MIN)
/* Overflow check. */
if (ra < 0 || (!SAMESIGN(a, b) && !SAMESIGN(r, a)))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("smallint out of range"))); errmsg("smallint out of range")));
ra = Abs(r);
PG_RETURN_INT16(ra); PG_RETURN_INT16(ra);
} }
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include "btree_gist.h" #include "btree_gist.h"
#include "btree_utils_num.h" #include "btree_utils_num.h"
#include "common/int.h"
typedef struct int32key typedef struct int32key
{ {
...@@ -99,15 +100,14 @@ int4_dist(PG_FUNCTION_ARGS) ...@@ -99,15 +100,14 @@ int4_dist(PG_FUNCTION_ARGS)
int32 r; int32 r;
int32 ra; int32 ra;
r = a - b; if (pg_sub_s32_overflow(a, b, &r) ||
ra = Abs(r); r == INT32_MIN)
/* Overflow check. */
if (ra < 0 || (!SAMESIGN(a, b) && !SAMESIGN(r, a)))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer out of range"))); errmsg("integer out of range")));
ra = Abs(r);
PG_RETURN_INT32(ra); PG_RETURN_INT32(ra);
} }
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include "btree_gist.h" #include "btree_gist.h"
#include "btree_utils_num.h" #include "btree_utils_num.h"
#include "common/int.h"
typedef struct int64key typedef struct int64key
{ {
...@@ -99,15 +100,14 @@ int8_dist(PG_FUNCTION_ARGS) ...@@ -99,15 +100,14 @@ int8_dist(PG_FUNCTION_ARGS)
int64 r; int64 r;
int64 ra; int64 ra;
r = a - b; if (pg_sub_s64_overflow(a, b, &r) ||
ra = Abs(r); r == INT64_MIN)
/* Overflow check. */
if (ra < 0 || (!SAMESIGN(a, b) && !SAMESIGN(r, a)))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("bigint out of range"))); errmsg("bigint out of range")));
ra = Abs(r);
PG_RETURN_INT64(ra); PG_RETURN_INT64(ra);
} }
......
...@@ -89,8 +89,6 @@ typedef struct ...@@ -89,8 +89,6 @@ typedef struct
#define GET_FLOAT_DISTANCE(t, arg1, arg2) Abs( ((float8) *((const t *) (arg1))) - ((float8) *((const t *) (arg2))) ) #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 * check to see if a float4/8 val has underflowed or overflowed
* borrowed from src/backend/utils/adt/float.c * borrowed from src/backend/utils/adt/float.c
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "postgres.h" #include "postgres.h"
#include "catalog/pg_type.h" #include "catalog/pg_type.h"
#include "common/int.h"
#include "utils/array.h" #include "utils/array.h"
#include "utils/builtins.h" #include "utils/builtins.h"
#include "utils/lsyscache.h" #include "utils/lsyscache.h"
...@@ -118,15 +119,11 @@ array_append(PG_FUNCTION_ARGS) ...@@ -118,15 +119,11 @@ array_append(PG_FUNCTION_ARGS)
if (eah->ndims == 1) if (eah->ndims == 1)
{ {
/* append newelem */ /* append newelem */
int ub;
lb = eah->lbound; lb = eah->lbound;
dimv = eah->dims; dimv = eah->dims;
ub = dimv[0] + lb[0] - 1;
indx = ub + 1;
/* overflow? */ /* index of added elem is at lb[0] + (dimv[0] - 1) + 1 */
if (indx < ub) if (pg_add_s32_overflow(lb[0], dimv[0], &indx))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer out of range"))); errmsg("integer out of range")));
...@@ -176,11 +173,9 @@ array_prepend(PG_FUNCTION_ARGS) ...@@ -176,11 +173,9 @@ array_prepend(PG_FUNCTION_ARGS)
{ {
/* prepend newelem */ /* prepend newelem */
lb = eah->lbound; lb = eah->lbound;
indx = lb[0] - 1;
lb0 = lb[0]; lb0 = lb[0];
/* overflow? */ if (pg_sub_s32_overflow(lb0, 1, &indx))
if (indx > lb[0])
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer out of range"))); errmsg("integer out of range")));
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <ctype.h> #include <ctype.h>
#include <math.h> #include <math.h>
#include "common/int.h"
#include "libpq/pqformat.h" #include "libpq/pqformat.h"
#include "utils/builtins.h" #include "utils/builtins.h"
#include "utils/cash.h" #include "utils/cash.h"
...@@ -199,20 +200,21 @@ cash_in(PG_FUNCTION_ARGS) ...@@ -199,20 +200,21 @@ cash_in(PG_FUNCTION_ARGS)
for (; *s; s++) 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)) 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, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("value \"%s\" is out of range for type %s", errmsg("value \"%s\" is out of range for type %s",
str, "money"))); str, "money")));
value = newvalue;
if (seen_dot) if (seen_dot)
dec++; dec++;
} }
...@@ -230,26 +232,23 @@ cash_in(PG_FUNCTION_ARGS) ...@@ -230,26 +232,23 @@ cash_in(PG_FUNCTION_ARGS)
/* round off if there's another digit */ /* round off if there's another digit */
if (isdigit((unsigned char) *s) && *s >= '5') if (isdigit((unsigned char) *s) && *s >= '5')
value--; /* remember we build the value in the negative */ {
/* remember we build the value in the negative */
if (value > 0) if (pg_sub_s64_overflow(value, 1, &value))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("value \"%s\" is out of range for type %s", errmsg("value \"%s\" is out of range for type %s",
str, "money"))); str, "money")));
}
/* adjust for less than required decimal places */ /* adjust for less than required decimal places */
for (; dec < fpoint; dec++) for (; dec < fpoint; dec++)
{ {
Cash newvalue = value * 10; if (pg_mul_s64_overflow(value, 10, &value))
if (newvalue / 10 != value)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("value \"%s\" is out of range for type %s", errmsg("value \"%s\" is out of range for type %s",
str, "money"))); str, "money")));
value = newvalue;
} }
/* /*
...@@ -285,12 +284,12 @@ cash_in(PG_FUNCTION_ARGS) ...@@ -285,12 +284,12 @@ cash_in(PG_FUNCTION_ARGS)
*/ */
if (sgn > 0) if (sgn > 0)
{ {
result = -value; if (value == PG_INT64_MIN)
if (result < 0)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("value \"%s\" is out of range for type %s", errmsg("value \"%s\" is out of range for type %s",
str, "money"))); str, "money")));
result = -value;
} }
else else
result = value; result = value;
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <limits.h> #include <limits.h>
#include "catalog/pg_type.h" #include "catalog/pg_type.h"
#include "common/int.h"
#include "libpq/pqformat.h" #include "libpq/pqformat.h"
#include "utils/array.h" #include "utils/array.h"
#include "utils/builtins.h" #include "utils/builtins.h"
...@@ -3548,9 +3549,7 @@ width_bucket_float8(PG_FUNCTION_ARGS) ...@@ -3548,9 +3549,7 @@ width_bucket_float8(PG_FUNCTION_ARGS)
result = 0; result = 0;
else if (operand >= bound2) else if (operand >= bound2)
{ {
result = count + 1; if (pg_add_s32_overflow(count, 1, &result))
/* check for overflow */
if (result < count)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer out of range"))); errmsg("integer out of range")));
...@@ -3564,9 +3563,7 @@ width_bucket_float8(PG_FUNCTION_ARGS) ...@@ -3564,9 +3563,7 @@ width_bucket_float8(PG_FUNCTION_ARGS)
result = 0; result = 0;
else if (operand <= bound2) else if (operand <= bound2)
{ {
result = count + 1; if (pg_add_s32_overflow(count, 1, &result))
/* check for overflow */
if (result < count)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer out of range"))); errmsg("integer out of range")));
......
...@@ -32,14 +32,12 @@ ...@@ -32,14 +32,12 @@
#include <limits.h> #include <limits.h>
#include "catalog/pg_type.h" #include "catalog/pg_type.h"
#include "common/int.h"
#include "funcapi.h" #include "funcapi.h"
#include "libpq/pqformat.h" #include "libpq/pqformat.h"
#include "utils/array.h" #include "utils/array.h"
#include "utils/builtins.h" #include "utils/builtins.h"
#define SAMESIGN(a,b) (((a) < 0) == ((b) < 0))
#define Int2VectorSize(n) (offsetof(int2vector, values) + (n) * sizeof(int16)) #define Int2VectorSize(n) (offsetof(int2vector, values) + (n) * sizeof(int16))
typedef struct typedef struct
...@@ -328,7 +326,7 @@ i4toi2(PG_FUNCTION_ARGS) ...@@ -328,7 +326,7 @@ i4toi2(PG_FUNCTION_ARGS)
{ {
int32 arg1 = PG_GETARG_INT32(0); int32 arg1 = PG_GETARG_INT32(0);
if (arg1 < SHRT_MIN || arg1 > SHRT_MAX) if (unlikely(arg1 < SHRT_MIN) || unlikely(arg1 > SHRT_MAX))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("smallint out of range"))); errmsg("smallint out of range")));
...@@ -598,15 +596,12 @@ Datum ...@@ -598,15 +596,12 @@ Datum
int4um(PG_FUNCTION_ARGS) int4um(PG_FUNCTION_ARGS)
{ {
int32 arg = PG_GETARG_INT32(0); int32 arg = PG_GETARG_INT32(0);
int32 result;
result = -arg; if (unlikely(arg == PG_INT32_MIN))
/* overflow check (needed for INT_MIN) */
if (arg != 0 && SAMESIGN(result, arg))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer out of range"))); errmsg("integer out of range")));
PG_RETURN_INT32(result); PG_RETURN_INT32(-arg);
} }
Datum Datum
...@@ -624,14 +619,7 @@ int4pl(PG_FUNCTION_ARGS) ...@@ -624,14 +619,7 @@ int4pl(PG_FUNCTION_ARGS)
int32 arg2 = PG_GETARG_INT32(1); int32 arg2 = PG_GETARG_INT32(1);
int32 result; int32 result;
result = arg1 + arg2; if (unlikely(pg_add_s32_overflow(arg1, arg2, &result)))
/*
* 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))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer out of range"))); errmsg("integer out of range")));
...@@ -645,14 +633,7 @@ int4mi(PG_FUNCTION_ARGS) ...@@ -645,14 +633,7 @@ int4mi(PG_FUNCTION_ARGS)
int32 arg2 = PG_GETARG_INT32(1); int32 arg2 = PG_GETARG_INT32(1);
int32 result; int32 result;
result = arg1 - arg2; if (unlikely(pg_sub_s32_overflow(arg1, arg2, &result)))
/*
* 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))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer out of range"))); errmsg("integer out of range")));
...@@ -666,24 +647,7 @@ int4mul(PG_FUNCTION_ARGS) ...@@ -666,24 +647,7 @@ int4mul(PG_FUNCTION_ARGS)
int32 arg2 = PG_GETARG_INT32(1); int32 arg2 = PG_GETARG_INT32(1);
int32 result; int32 result;
result = arg1 * arg2; if (unlikely(pg_mul_s32_overflow(arg1, arg2, &result)))
/*
* 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))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer out of range"))); errmsg("integer out of range")));
...@@ -714,12 +678,11 @@ int4div(PG_FUNCTION_ARGS) ...@@ -714,12 +678,11 @@ int4div(PG_FUNCTION_ARGS)
*/ */
if (arg2 == -1) if (arg2 == -1)
{ {
result = -arg1; if (unlikely(arg1 == PG_INT32_MIN))
/* overflow check (needed for INT_MIN) */
if (arg1 != 0 && SAMESIGN(result, arg1))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer out of range"))); errmsg("integer out of range")));
result = -arg1;
PG_RETURN_INT32(result); PG_RETURN_INT32(result);
} }
...@@ -736,9 +699,7 @@ int4inc(PG_FUNCTION_ARGS) ...@@ -736,9 +699,7 @@ int4inc(PG_FUNCTION_ARGS)
int32 arg = PG_GETARG_INT32(0); int32 arg = PG_GETARG_INT32(0);
int32 result; int32 result;
result = arg + 1; if (unlikely(pg_add_s32_overflow(arg, 1, &result)))
/* Overflow check */
if (arg > 0 && result < 0)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer out of range"))); errmsg("integer out of range")));
...@@ -750,15 +711,12 @@ Datum ...@@ -750,15 +711,12 @@ Datum
int2um(PG_FUNCTION_ARGS) int2um(PG_FUNCTION_ARGS)
{ {
int16 arg = PG_GETARG_INT16(0); int16 arg = PG_GETARG_INT16(0);
int16 result;
result = -arg; if (unlikely(arg == PG_INT16_MIN))
/* overflow check (needed for SHRT_MIN) */
if (arg != 0 && SAMESIGN(result, arg))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("smallint out of range"))); errmsg("smallint out of range")));
PG_RETURN_INT16(result); PG_RETURN_INT16(-arg);
} }
Datum Datum
...@@ -776,14 +734,7 @@ int2pl(PG_FUNCTION_ARGS) ...@@ -776,14 +734,7 @@ int2pl(PG_FUNCTION_ARGS)
int16 arg2 = PG_GETARG_INT16(1); int16 arg2 = PG_GETARG_INT16(1);
int16 result; int16 result;
result = arg1 + arg2; if (unlikely(pg_add_s16_overflow(arg1, arg2, &result)))
/*
* 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))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("smallint out of range"))); errmsg("smallint out of range")));
...@@ -797,14 +748,7 @@ int2mi(PG_FUNCTION_ARGS) ...@@ -797,14 +748,7 @@ int2mi(PG_FUNCTION_ARGS)
int16 arg2 = PG_GETARG_INT16(1); int16 arg2 = PG_GETARG_INT16(1);
int16 result; int16 result;
result = arg1 - arg2; if (unlikely(pg_sub_s16_overflow(arg1, arg2, &result)))
/*
* 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))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("smallint out of range"))); errmsg("smallint out of range")));
...@@ -816,20 +760,14 @@ int2mul(PG_FUNCTION_ARGS) ...@@ -816,20 +760,14 @@ int2mul(PG_FUNCTION_ARGS)
{ {
int16 arg1 = PG_GETARG_INT16(0); int16 arg1 = PG_GETARG_INT16(0);
int16 arg2 = PG_GETARG_INT16(1); 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, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("smallint out of range"))); errmsg("smallint out of range")));
PG_RETURN_INT16((int16) result32); PG_RETURN_INT16(result);
} }
Datum Datum
...@@ -856,12 +794,11 @@ int2div(PG_FUNCTION_ARGS) ...@@ -856,12 +794,11 @@ int2div(PG_FUNCTION_ARGS)
*/ */
if (arg2 == -1) if (arg2 == -1)
{ {
result = -arg1; if (unlikely(arg1 == INT16_MIN))
/* overflow check (needed for SHRT_MIN) */
if (arg1 != 0 && SAMESIGN(result, arg1))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("smallint out of range"))); errmsg("smallint out of range")));
result = -arg1;
PG_RETURN_INT16(result); PG_RETURN_INT16(result);
} }
...@@ -879,14 +816,7 @@ int24pl(PG_FUNCTION_ARGS) ...@@ -879,14 +816,7 @@ int24pl(PG_FUNCTION_ARGS)
int32 arg2 = PG_GETARG_INT32(1); int32 arg2 = PG_GETARG_INT32(1);
int32 result; int32 result;
result = arg1 + arg2; if (unlikely(pg_add_s32_overflow((int32) arg1, arg2, &result)))
/*
* 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))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer out of range"))); errmsg("integer out of range")));
...@@ -900,14 +830,7 @@ int24mi(PG_FUNCTION_ARGS) ...@@ -900,14 +830,7 @@ int24mi(PG_FUNCTION_ARGS)
int32 arg2 = PG_GETARG_INT32(1); int32 arg2 = PG_GETARG_INT32(1);
int32 result; int32 result;
result = arg1 - arg2; if (unlikely(pg_sub_s32_overflow((int32) arg1, arg2, &result)))
/*
* 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))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer out of range"))); errmsg("integer out of range")));
...@@ -921,20 +844,7 @@ int24mul(PG_FUNCTION_ARGS) ...@@ -921,20 +844,7 @@ int24mul(PG_FUNCTION_ARGS)
int32 arg2 = PG_GETARG_INT32(1); int32 arg2 = PG_GETARG_INT32(1);
int32 result; int32 result;
result = arg1 * arg2; if (unlikely(pg_mul_s32_overflow((int32) arg1, arg2, &result)))
/*
* 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)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer out of range"))); errmsg("integer out of range")));
...@@ -947,7 +857,7 @@ int24div(PG_FUNCTION_ARGS) ...@@ -947,7 +857,7 @@ int24div(PG_FUNCTION_ARGS)
int16 arg1 = PG_GETARG_INT16(0); int16 arg1 = PG_GETARG_INT16(0);
int32 arg2 = PG_GETARG_INT32(1); int32 arg2 = PG_GETARG_INT32(1);
if (arg2 == 0) if (unlikely(arg2 == 0))
{ {
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_DIVISION_BY_ZERO), (errcode(ERRCODE_DIVISION_BY_ZERO),
...@@ -967,14 +877,7 @@ int42pl(PG_FUNCTION_ARGS) ...@@ -967,14 +877,7 @@ int42pl(PG_FUNCTION_ARGS)
int16 arg2 = PG_GETARG_INT16(1); int16 arg2 = PG_GETARG_INT16(1);
int32 result; int32 result;
result = arg1 + arg2; if (unlikely(pg_add_s32_overflow(arg1, (int32) arg2, &result)))
/*
* 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))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer out of range"))); errmsg("integer out of range")));
...@@ -988,14 +891,7 @@ int42mi(PG_FUNCTION_ARGS) ...@@ -988,14 +891,7 @@ int42mi(PG_FUNCTION_ARGS)
int16 arg2 = PG_GETARG_INT16(1); int16 arg2 = PG_GETARG_INT16(1);
int32 result; int32 result;
result = arg1 - arg2; if (unlikely(pg_sub_s32_overflow(arg1, (int32) arg2, &result)))
/*
* 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))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer out of range"))); errmsg("integer out of range")));
...@@ -1009,20 +905,7 @@ int42mul(PG_FUNCTION_ARGS) ...@@ -1009,20 +905,7 @@ int42mul(PG_FUNCTION_ARGS)
int16 arg2 = PG_GETARG_INT16(1); int16 arg2 = PG_GETARG_INT16(1);
int32 result; int32 result;
result = arg1 * arg2; if (unlikely(pg_mul_s32_overflow(arg1, (int32) arg2, &result)))
/*
* 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)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer out of range"))); errmsg("integer out of range")));
...@@ -1036,7 +919,7 @@ int42div(PG_FUNCTION_ARGS) ...@@ -1036,7 +919,7 @@ int42div(PG_FUNCTION_ARGS)
int16 arg2 = PG_GETARG_INT16(1); int16 arg2 = PG_GETARG_INT16(1);
int32 result; int32 result;
if (arg2 == 0) if (unlikely(arg2 == 0))
{ {
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_DIVISION_BY_ZERO), (errcode(ERRCODE_DIVISION_BY_ZERO),
...@@ -1053,12 +936,11 @@ int42div(PG_FUNCTION_ARGS) ...@@ -1053,12 +936,11 @@ int42div(PG_FUNCTION_ARGS)
*/ */
if (arg2 == -1) if (arg2 == -1)
{ {
result = -arg1; if (unlikely(arg1 == PG_INT32_MIN))
/* overflow check (needed for INT_MIN) */
if (arg1 != 0 && SAMESIGN(result, arg1))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer out of range"))); errmsg("integer out of range")));
result = -arg1;
PG_RETURN_INT32(result); PG_RETURN_INT32(result);
} }
...@@ -1075,7 +957,7 @@ int4mod(PG_FUNCTION_ARGS) ...@@ -1075,7 +957,7 @@ int4mod(PG_FUNCTION_ARGS)
int32 arg1 = PG_GETARG_INT32(0); int32 arg1 = PG_GETARG_INT32(0);
int32 arg2 = PG_GETARG_INT32(1); int32 arg2 = PG_GETARG_INT32(1);
if (arg2 == 0) if (unlikely(arg2 == 0))
{ {
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_DIVISION_BY_ZERO), (errcode(ERRCODE_DIVISION_BY_ZERO),
...@@ -1103,7 +985,7 @@ int2mod(PG_FUNCTION_ARGS) ...@@ -1103,7 +985,7 @@ int2mod(PG_FUNCTION_ARGS)
int16 arg1 = PG_GETARG_INT16(0); int16 arg1 = PG_GETARG_INT16(0);
int16 arg2 = PG_GETARG_INT16(1); int16 arg2 = PG_GETARG_INT16(1);
if (arg2 == 0) if (unlikely(arg2 == 0))
{ {
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_DIVISION_BY_ZERO), (errcode(ERRCODE_DIVISION_BY_ZERO),
...@@ -1136,12 +1018,11 @@ int4abs(PG_FUNCTION_ARGS) ...@@ -1136,12 +1018,11 @@ int4abs(PG_FUNCTION_ARGS)
int32 arg1 = PG_GETARG_INT32(0); int32 arg1 = PG_GETARG_INT32(0);
int32 result; int32 result;
result = (arg1 < 0) ? -arg1 : arg1; if (unlikely(arg1 == INT32_MIN))
/* overflow check (needed for INT_MIN) */
if (result < 0)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer out of range"))); errmsg("integer out of range")));
result = (arg1 < 0) ? -arg1 : arg1;
PG_RETURN_INT32(result); PG_RETURN_INT32(result);
} }
...@@ -1151,12 +1032,11 @@ int2abs(PG_FUNCTION_ARGS) ...@@ -1151,12 +1032,11 @@ int2abs(PG_FUNCTION_ARGS)
int16 arg1 = PG_GETARG_INT16(0); int16 arg1 = PG_GETARG_INT16(0);
int16 result; int16 result;
result = (arg1 < 0) ? -arg1 : arg1; if (unlikely(arg1 == INT16_MIN))
/* overflow check (needed for SHRT_MIN) */
if (result < 0)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("smallint out of range"))); errmsg("smallint out of range")));
result = (arg1 < 0) ? -arg1 : arg1;
PG_RETURN_INT16(result); PG_RETURN_INT16(result);
} }
...@@ -1381,11 +1261,11 @@ generate_series_step_int4(PG_FUNCTION_ARGS) ...@@ -1381,11 +1261,11 @@ generate_series_step_int4(PG_FUNCTION_ARGS)
if ((fctx->step > 0 && fctx->current <= fctx->finish) || if ((fctx->step > 0 && fctx->current <= fctx->finish) ||
(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; * Increment current in preparation for next iteration. If next-value
* computation overflows, this is the final result.
/* if next-value computation overflows, this is the final result */ */
if (SAMESIGN(result, fctx->step) && !SAMESIGN(result, fctx->current)) if (pg_add_s32_overflow(fctx->current, fctx->step, &fctx->current))
fctx->step = 0; fctx->step = 0;
/* do when there is more left to send */ /* do when there is more left to send */
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <limits.h> #include <limits.h>
#include <math.h> #include <math.h>
#include "common/int.h"
#include "funcapi.h" #include "funcapi.h"
#include "libpq/pqformat.h" #include "libpq/pqformat.h"
#include "utils/int8.h" #include "utils/int8.h"
...@@ -25,8 +26,6 @@ ...@@ -25,8 +26,6 @@
#define MAXINT8LEN 25 #define MAXINT8LEN 25
#define SAMESIGN(a,b) (((a) < 0) == ((b) < 0))
typedef struct typedef struct
{ {
int64 current; int64 current;
...@@ -56,11 +55,14 @@ scanint8(const char *str, bool errorOK, int64 *result) ...@@ -56,11 +55,14 @@ scanint8(const char *str, bool errorOK, int64 *result)
{ {
const char *ptr = str; const char *ptr = str;
int64 tmp = 0; int64 tmp = 0;
int sign = 1; bool neg = false;
/* /*
* Do our own scan, rather than relying on sscanf which might be broken * Do our own scan, rather than relying on sscanf which might be broken
* for long long. * 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 */ /* skip leading spaces */
...@@ -71,41 +73,45 @@ scanint8(const char *str, bool errorOK, int64 *result) ...@@ -71,41 +73,45 @@ scanint8(const char *str, bool errorOK, int64 *result)
if (*ptr == '-') if (*ptr == '-')
{ {
ptr++; ptr++;
neg = true;
/*
* 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;
} }
else if (*ptr == '+') else if (*ptr == '+')
ptr++; ptr++;
/* require at least one digit */ /* require at least one digit */
if (!isdigit((unsigned char) *ptr)) if (unlikely(!isdigit((unsigned char) *ptr)))
{ {
if (errorOK) goto invalid_syntax;
return false;
else
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for integer: \"%s\"",
str)));
} }
/* process digits */ /* process digits */
while (*ptr && isdigit((unsigned char) *ptr)) while (*ptr && isdigit((unsigned char) *ptr))
{ {
int64 newtmp = tmp * 10 + (*ptr++ - '0'); int8 digit = (*ptr++ - '0');
if (unlikely(pg_mul_s64_overflow(tmp, 10, &tmp)) ||
unlikely(pg_sub_s64_overflow(tmp, digit, &tmp)))
goto out_of_range;
}
if ((newtmp / 10) != tmp) /* overflow? */ /* allow trailing whitespace, but not other trailing chars */
while (*ptr != '\0' && isspace((unsigned char) *ptr))
ptr++;
if (unlikely(*ptr != '\0'))
goto invalid_syntax;
if (!neg)
{ {
if (unlikely(tmp == INT64_MIN))
goto out_of_range;
tmp = -tmp;
}
*result = tmp;
return true;
out_of_range:
if (errorOK) if (errorOK)
return false; return false;
else else
...@@ -113,18 +119,7 @@ scanint8(const char *str, bool errorOK, int64 *result) ...@@ -113,18 +119,7 @@ scanint8(const char *str, bool errorOK, int64 *result)
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("value \"%s\" is out of range for type %s", errmsg("value \"%s\" is out of range for type %s",
str, "bigint"))); str, "bigint")));
} invalid_syntax:
tmp = newtmp;
}
gotdigits:
/* allow trailing whitespace, but not other trailing chars */
while (*ptr != '\0' && isspace((unsigned char) *ptr))
ptr++;
if (*ptr != '\0')
{
if (errorOK) if (errorOK)
return false; return false;
else else
...@@ -132,11 +127,6 @@ gotdigits: ...@@ -132,11 +127,6 @@ gotdigits:
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for integer: \"%s\"", errmsg("invalid input syntax for integer: \"%s\"",
str))); str)));
}
*result = (sign < 0) ? -tmp : tmp;
return true;
} }
/* int8in() /* int8in()
...@@ -492,12 +482,11 @@ int8um(PG_FUNCTION_ARGS) ...@@ -492,12 +482,11 @@ int8um(PG_FUNCTION_ARGS)
int64 arg = PG_GETARG_INT64(0); int64 arg = PG_GETARG_INT64(0);
int64 result; int64 result;
result = -arg; if (unlikely(arg == PG_INT64_MIN))
/* overflow check (needed for INT64_MIN) */
if (arg != 0 && SAMESIGN(result, arg))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("bigint out of range"))); errmsg("bigint out of range")));
result = -arg;
PG_RETURN_INT64(result); PG_RETURN_INT64(result);
} }
...@@ -516,14 +505,7 @@ int8pl(PG_FUNCTION_ARGS) ...@@ -516,14 +505,7 @@ int8pl(PG_FUNCTION_ARGS)
int64 arg2 = PG_GETARG_INT64(1); int64 arg2 = PG_GETARG_INT64(1);
int64 result; int64 result;
result = arg1 + arg2; if (unlikely(pg_add_s64_overflow(arg1, arg2, &result)))
/*
* 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))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("bigint out of range"))); errmsg("bigint out of range")));
...@@ -537,14 +519,7 @@ int8mi(PG_FUNCTION_ARGS) ...@@ -537,14 +519,7 @@ int8mi(PG_FUNCTION_ARGS)
int64 arg2 = PG_GETARG_INT64(1); int64 arg2 = PG_GETARG_INT64(1);
int64 result; int64 result;
result = arg1 - arg2; if (unlikely(pg_sub_s64_overflow(arg1, arg2, &result)))
/*
* 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))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("bigint out of range"))); errmsg("bigint out of range")));
...@@ -558,28 +533,10 @@ int8mul(PG_FUNCTION_ARGS) ...@@ -558,28 +533,10 @@ int8mul(PG_FUNCTION_ARGS)
int64 arg2 = PG_GETARG_INT64(1); int64 arg2 = PG_GETARG_INT64(1);
int64 result; int64 result;
result = arg1 * arg2; if (unlikely(pg_mul_s64_overflow(arg1, arg2, &result)))
/*
* 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, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("bigint out of range"))); errmsg("bigint out of range")));
}
PG_RETURN_INT64(result); PG_RETURN_INT64(result);
} }
...@@ -607,12 +564,11 @@ int8div(PG_FUNCTION_ARGS) ...@@ -607,12 +564,11 @@ int8div(PG_FUNCTION_ARGS)
*/ */
if (arg2 == -1) if (arg2 == -1)
{ {
result = -arg1; if (unlikely(arg1 == INT64_MIN))
/* overflow check (needed for INT64_MIN) */
if (arg1 != 0 && SAMESIGN(result, arg1))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("bigint out of range"))); errmsg("bigint out of range")));
result = -arg1;
PG_RETURN_INT64(result); PG_RETURN_INT64(result);
} }
...@@ -632,12 +588,11 @@ int8abs(PG_FUNCTION_ARGS) ...@@ -632,12 +588,11 @@ int8abs(PG_FUNCTION_ARGS)
int64 arg1 = PG_GETARG_INT64(0); int64 arg1 = PG_GETARG_INT64(0);
int64 result; int64 result;
result = (arg1 < 0) ? -arg1 : arg1; if (unlikely(arg1 == INT64_MIN))
/* overflow check (needed for INT64_MIN) */
if (result < 0)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("bigint out of range"))); errmsg("bigint out of range")));
result = (arg1 < 0) ? -arg1 : arg1;
PG_RETURN_INT64(result); PG_RETURN_INT64(result);
} }
...@@ -650,7 +605,7 @@ int8mod(PG_FUNCTION_ARGS) ...@@ -650,7 +605,7 @@ int8mod(PG_FUNCTION_ARGS)
int64 arg1 = PG_GETARG_INT64(0); int64 arg1 = PG_GETARG_INT64(0);
int64 arg2 = PG_GETARG_INT64(1); int64 arg2 = PG_GETARG_INT64(1);
if (arg2 == 0) if (unlikely(arg2 == 0))
{ {
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_DIVISION_BY_ZERO), (errcode(ERRCODE_DIVISION_BY_ZERO),
...@@ -687,16 +642,12 @@ int8inc(PG_FUNCTION_ARGS) ...@@ -687,16 +642,12 @@ int8inc(PG_FUNCTION_ARGS)
if (AggCheckCallContext(fcinfo, NULL)) if (AggCheckCallContext(fcinfo, NULL))
{ {
int64 *arg = (int64 *) PG_GETARG_POINTER(0); int64 *arg = (int64 *) PG_GETARG_POINTER(0);
int64 result;
result = *arg + 1; if (unlikely(pg_add_s64_overflow(*arg, 1, arg)))
/* Overflow check */
if (result < 0 && *arg > 0)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("bigint out of range"))); errmsg("bigint out of range")));
*arg = result;
PG_RETURN_POINTER(arg); PG_RETURN_POINTER(arg);
} }
else else
...@@ -706,9 +657,7 @@ int8inc(PG_FUNCTION_ARGS) ...@@ -706,9 +657,7 @@ int8inc(PG_FUNCTION_ARGS)
int64 arg = PG_GETARG_INT64(0); int64 arg = PG_GETARG_INT64(0);
int64 result; int64 result;
result = arg + 1; if (unlikely(pg_add_s64_overflow(arg, 1, &result)))
/* Overflow check */
if (result < 0 && arg > 0)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("bigint out of range"))); errmsg("bigint out of range")));
...@@ -731,16 +680,11 @@ int8dec(PG_FUNCTION_ARGS) ...@@ -731,16 +680,11 @@ int8dec(PG_FUNCTION_ARGS)
if (AggCheckCallContext(fcinfo, NULL)) if (AggCheckCallContext(fcinfo, NULL))
{ {
int64 *arg = (int64 *) PG_GETARG_POINTER(0); int64 *arg = (int64 *) PG_GETARG_POINTER(0);
int64 result;
result = *arg - 1; if (unlikely(pg_sub_s64_overflow(*arg, 1, arg)))
/* Overflow check */
if (result > 0 && *arg < 0)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("bigint out of range"))); errmsg("bigint out of range")));
*arg = result;
PG_RETURN_POINTER(arg); PG_RETURN_POINTER(arg);
} }
else else
...@@ -750,9 +694,7 @@ int8dec(PG_FUNCTION_ARGS) ...@@ -750,9 +694,7 @@ int8dec(PG_FUNCTION_ARGS)
int64 arg = PG_GETARG_INT64(0); int64 arg = PG_GETARG_INT64(0);
int64 result; int64 result;
result = arg - 1; if (unlikely(pg_sub_s64_overflow(arg, 1, &result)))
/* Overflow check */
if (result > 0 && arg < 0)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("bigint out of range"))); errmsg("bigint out of range")));
...@@ -821,14 +763,7 @@ int84pl(PG_FUNCTION_ARGS) ...@@ -821,14 +763,7 @@ int84pl(PG_FUNCTION_ARGS)
int32 arg2 = PG_GETARG_INT32(1); int32 arg2 = PG_GETARG_INT32(1);
int64 result; int64 result;
result = arg1 + arg2; if (unlikely(pg_add_s64_overflow(arg1, (int64) arg2, &result)))
/*
* 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))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("bigint out of range"))); errmsg("bigint out of range")));
...@@ -842,14 +777,7 @@ int84mi(PG_FUNCTION_ARGS) ...@@ -842,14 +777,7 @@ int84mi(PG_FUNCTION_ARGS)
int32 arg2 = PG_GETARG_INT32(1); int32 arg2 = PG_GETARG_INT32(1);
int64 result; int64 result;
result = arg1 - arg2; if (unlikely(pg_sub_s64_overflow(arg1, (int64) arg2, &result)))
/*
* 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))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("bigint out of range"))); errmsg("bigint out of range")));
...@@ -863,20 +791,7 @@ int84mul(PG_FUNCTION_ARGS) ...@@ -863,20 +791,7 @@ int84mul(PG_FUNCTION_ARGS)
int32 arg2 = PG_GETARG_INT32(1); int32 arg2 = PG_GETARG_INT32(1);
int64 result; int64 result;
result = arg1 * arg2; if (unlikely(pg_mul_s64_overflow(arg1, (int64) arg2, &result)))
/*
* 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)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("bigint out of range"))); errmsg("bigint out of range")));
...@@ -907,12 +822,11 @@ int84div(PG_FUNCTION_ARGS) ...@@ -907,12 +822,11 @@ int84div(PG_FUNCTION_ARGS)
*/ */
if (arg2 == -1) if (arg2 == -1)
{ {
result = -arg1; if (unlikely(arg1 == INT64_MIN))
/* overflow check (needed for INT64_MIN) */
if (arg1 != 0 && SAMESIGN(result, arg1))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("bigint out of range"))); errmsg("bigint out of range")));
result = -arg1;
PG_RETURN_INT64(result); PG_RETURN_INT64(result);
} }
...@@ -930,14 +844,7 @@ int48pl(PG_FUNCTION_ARGS) ...@@ -930,14 +844,7 @@ int48pl(PG_FUNCTION_ARGS)
int64 arg2 = PG_GETARG_INT64(1); int64 arg2 = PG_GETARG_INT64(1);
int64 result; int64 result;
result = arg1 + arg2; if (unlikely(pg_add_s64_overflow((int64) arg1, arg2, &result)))
/*
* 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))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("bigint out of range"))); errmsg("bigint out of range")));
...@@ -951,14 +858,7 @@ int48mi(PG_FUNCTION_ARGS) ...@@ -951,14 +858,7 @@ int48mi(PG_FUNCTION_ARGS)
int64 arg2 = PG_GETARG_INT64(1); int64 arg2 = PG_GETARG_INT64(1);
int64 result; int64 result;
result = arg1 - arg2; if (unlikely(pg_sub_s64_overflow((int64) arg1, arg2, &result)))
/*
* 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))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("bigint out of range"))); errmsg("bigint out of range")));
...@@ -972,20 +872,7 @@ int48mul(PG_FUNCTION_ARGS) ...@@ -972,20 +872,7 @@ int48mul(PG_FUNCTION_ARGS)
int64 arg2 = PG_GETARG_INT64(1); int64 arg2 = PG_GETARG_INT64(1);
int64 result; int64 result;
result = arg1 * arg2; if (unlikely(pg_mul_s64_overflow((int64) arg1, arg2, &result)))
/*
* 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)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("bigint out of range"))); errmsg("bigint out of range")));
...@@ -998,7 +885,7 @@ int48div(PG_FUNCTION_ARGS) ...@@ -998,7 +885,7 @@ int48div(PG_FUNCTION_ARGS)
int32 arg1 = PG_GETARG_INT32(0); int32 arg1 = PG_GETARG_INT32(0);
int64 arg2 = PG_GETARG_INT64(1); int64 arg2 = PG_GETARG_INT64(1);
if (arg2 == 0) if (unlikely(arg2 == 0))
{ {
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_DIVISION_BY_ZERO), (errcode(ERRCODE_DIVISION_BY_ZERO),
...@@ -1018,14 +905,7 @@ int82pl(PG_FUNCTION_ARGS) ...@@ -1018,14 +905,7 @@ int82pl(PG_FUNCTION_ARGS)
int16 arg2 = PG_GETARG_INT16(1); int16 arg2 = PG_GETARG_INT16(1);
int64 result; int64 result;
result = arg1 + arg2; if (unlikely(pg_add_s64_overflow(arg1, (int64) arg2, &result)))
/*
* 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))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("bigint out of range"))); errmsg("bigint out of range")));
...@@ -1039,14 +919,7 @@ int82mi(PG_FUNCTION_ARGS) ...@@ -1039,14 +919,7 @@ int82mi(PG_FUNCTION_ARGS)
int16 arg2 = PG_GETARG_INT16(1); int16 arg2 = PG_GETARG_INT16(1);
int64 result; int64 result;
result = arg1 - arg2; if (unlikely(pg_sub_s64_overflow(arg1, (int64) arg2, &result)))
/*
* 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))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("bigint out of range"))); errmsg("bigint out of range")));
...@@ -1060,20 +933,7 @@ int82mul(PG_FUNCTION_ARGS) ...@@ -1060,20 +933,7 @@ int82mul(PG_FUNCTION_ARGS)
int16 arg2 = PG_GETARG_INT16(1); int16 arg2 = PG_GETARG_INT16(1);
int64 result; int64 result;
result = arg1 * arg2; if (unlikely(pg_mul_s64_overflow(arg1, (int64) arg2, &result)))
/*
* 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)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("bigint out of range"))); errmsg("bigint out of range")));
...@@ -1087,7 +947,7 @@ int82div(PG_FUNCTION_ARGS) ...@@ -1087,7 +947,7 @@ int82div(PG_FUNCTION_ARGS)
int16 arg2 = PG_GETARG_INT16(1); int16 arg2 = PG_GETARG_INT16(1);
int64 result; int64 result;
if (arg2 == 0) if (unlikely(arg2 == 0))
{ {
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_DIVISION_BY_ZERO), (errcode(ERRCODE_DIVISION_BY_ZERO),
...@@ -1104,12 +964,11 @@ int82div(PG_FUNCTION_ARGS) ...@@ -1104,12 +964,11 @@ int82div(PG_FUNCTION_ARGS)
*/ */
if (arg2 == -1) if (arg2 == -1)
{ {
result = -arg1; if (unlikely(arg1 == INT64_MIN))
/* overflow check (needed for INT64_MIN) */
if (arg1 != 0 && SAMESIGN(result, arg1))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("bigint out of range"))); errmsg("bigint out of range")));
result = -arg1;
PG_RETURN_INT64(result); PG_RETURN_INT64(result);
} }
...@@ -1127,14 +986,7 @@ int28pl(PG_FUNCTION_ARGS) ...@@ -1127,14 +986,7 @@ int28pl(PG_FUNCTION_ARGS)
int64 arg2 = PG_GETARG_INT64(1); int64 arg2 = PG_GETARG_INT64(1);
int64 result; int64 result;
result = arg1 + arg2; if (unlikely(pg_add_s64_overflow((int64) arg1, arg2, &result)))
/*
* 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))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("bigint out of range"))); errmsg("bigint out of range")));
...@@ -1148,14 +1000,7 @@ int28mi(PG_FUNCTION_ARGS) ...@@ -1148,14 +1000,7 @@ int28mi(PG_FUNCTION_ARGS)
int64 arg2 = PG_GETARG_INT64(1); int64 arg2 = PG_GETARG_INT64(1);
int64 result; int64 result;
result = arg1 - arg2; if (unlikely(pg_sub_s64_overflow((int64) arg1, arg2, &result)))
/*
* 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))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("bigint out of range"))); errmsg("bigint out of range")));
...@@ -1169,20 +1014,7 @@ int28mul(PG_FUNCTION_ARGS) ...@@ -1169,20 +1014,7 @@ int28mul(PG_FUNCTION_ARGS)
int64 arg2 = PG_GETARG_INT64(1); int64 arg2 = PG_GETARG_INT64(1);
int64 result; int64 result;
result = arg1 * arg2; if (unlikely(pg_mul_s64_overflow((int64) arg1, arg2, &result)))
/*
* 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)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("bigint out of range"))); errmsg("bigint out of range")));
...@@ -1195,7 +1027,7 @@ int28div(PG_FUNCTION_ARGS) ...@@ -1195,7 +1027,7 @@ int28div(PG_FUNCTION_ARGS)
int16 arg1 = PG_GETARG_INT16(0); int16 arg1 = PG_GETARG_INT16(0);
int64 arg2 = PG_GETARG_INT64(1); int64 arg2 = PG_GETARG_INT64(1);
if (arg2 == 0) if (unlikely(arg2 == 0))
{ {
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_DIVISION_BY_ZERO), (errcode(ERRCODE_DIVISION_BY_ZERO),
...@@ -1287,17 +1119,13 @@ Datum ...@@ -1287,17 +1119,13 @@ Datum
int84(PG_FUNCTION_ARGS) int84(PG_FUNCTION_ARGS)
{ {
int64 arg = PG_GETARG_INT64(0); int64 arg = PG_GETARG_INT64(0);
int32 result;
result = (int32) arg; if (unlikely(arg < PG_INT32_MIN) || unlikely(arg > PG_INT32_MAX))
/* Test for overflow by reverse-conversion. */
if ((int64) result != arg)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer out of range"))); errmsg("integer out of range")));
PG_RETURN_INT32(result); PG_RETURN_INT32((int32) arg);
} }
Datum Datum
...@@ -1312,17 +1140,13 @@ Datum ...@@ -1312,17 +1140,13 @@ Datum
int82(PG_FUNCTION_ARGS) int82(PG_FUNCTION_ARGS)
{ {
int64 arg = PG_GETARG_INT64(0); int64 arg = PG_GETARG_INT64(0);
int16 result;
result = (int16) arg;
/* Test for overflow by reverse-conversion. */ if (unlikely(arg < PG_INT16_MIN) || unlikely(arg > PG_INT16_MAX))
if ((int64) result != arg)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("smallint out of range"))); errmsg("smallint out of range")));
PG_RETURN_INT16(result); PG_RETURN_INT16((int16) arg);
} }
Datum Datum
...@@ -1348,18 +1172,15 @@ dtoi8(PG_FUNCTION_ARGS) ...@@ -1348,18 +1172,15 @@ dtoi8(PG_FUNCTION_ARGS)
/* Round arg to nearest integer (but it's still in float form) */ /* Round arg to nearest integer (but it's still in float form) */
arg = rint(arg); arg = rint(arg);
/* if (unlikely(arg < (double) PG_INT64_MIN) ||
* Does it fit in an int64? Avoid assuming that we have handy constants unlikely(arg > (double) PG_INT64_MAX) ||
* defined for the range boundaries, instead test for overflow by unlikely(isnan(arg)))
* reverse-conversion.
*/
result = (int64) arg;
if ((float8) result != arg)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("bigint out of range"))); errmsg("bigint out of range")));
result = (int64) arg;
PG_RETURN_INT64(result); PG_RETURN_INT64(result);
} }
...@@ -1381,42 +1202,32 @@ Datum ...@@ -1381,42 +1202,32 @@ Datum
ftoi8(PG_FUNCTION_ARGS) ftoi8(PG_FUNCTION_ARGS)
{ {
float4 arg = PG_GETARG_FLOAT4(0); float4 arg = PG_GETARG_FLOAT4(0);
int64 result;
float8 darg; float8 darg;
/* Round arg to nearest integer (but it's still in float form) */ /* Round arg to nearest integer (but it's still in float form) */
darg = rint(arg); darg = rint(arg);
/* if (unlikely(arg < (float4) PG_INT64_MIN) ||
* Does it fit in an int64? Avoid assuming that we have handy constants unlikely(arg > (float4) PG_INT64_MAX) ||
* defined for the range boundaries, instead test for overflow by unlikely(isnan(arg)))
* reverse-conversion.
*/
result = (int64) darg;
if ((float8) result != darg)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("bigint out of range"))); errmsg("bigint out of range")));
PG_RETURN_INT64(result); PG_RETURN_INT64((int64) darg);
} }
Datum Datum
i8tooid(PG_FUNCTION_ARGS) i8tooid(PG_FUNCTION_ARGS)
{ {
int64 arg = PG_GETARG_INT64(0); int64 arg = PG_GETARG_INT64(0);
Oid result;
result = (Oid) arg;
/* Test for overflow by reverse-conversion. */ if (unlikely(arg < 0) || unlikely(arg > PG_UINT32_MAX))
if ((int64) result != arg)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("OID out of range"))); errmsg("OID out of range")));
PG_RETURN_OID(result); PG_RETURN_OID((Oid) arg);
} }
Datum Datum
...@@ -1494,11 +1305,11 @@ generate_series_step_int8(PG_FUNCTION_ARGS) ...@@ -1494,11 +1305,11 @@ generate_series_step_int8(PG_FUNCTION_ARGS)
if ((fctx->step > 0 && fctx->current <= fctx->finish) || if ((fctx->step > 0 && fctx->current <= fctx->finish) ||
(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; * Increment current in preparation for next iteration. If next-value
* computation overflows, this is the final result.
/* if next-value computation overflows, this is the final result */ */
if (SAMESIGN(result, fctx->step) && !SAMESIGN(result, fctx->current)) if (pg_add_s64_overflow(fctx->current, fctx->step, &fctx->current))
fctx->step = 0; fctx->step = 0;
/* do when there is more left to send */ /* do when there is more left to send */
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include "access/hash.h" #include "access/hash.h"
#include "catalog/pg_type.h" #include "catalog/pg_type.h"
#include "common/int.h"
#include "funcapi.h" #include "funcapi.h"
#include "lib/hyperloglog.h" #include "lib/hyperloglog.h"
#include "libpq/pqformat.h" #include "libpq/pqformat.h"
...@@ -6169,8 +6170,7 @@ numericvar_to_int64(const NumericVar *var, int64 *result) ...@@ -6169,8 +6170,7 @@ numericvar_to_int64(const NumericVar *var, int64 *result)
int ndigits; int ndigits;
int weight; int weight;
int i; int i;
int64 val, int64 val;
oldval;
bool neg; bool neg;
NumericVar rounded; NumericVar rounded;
...@@ -6196,27 +6196,25 @@ numericvar_to_int64(const NumericVar *var, int64 *result) ...@@ -6196,27 +6196,25 @@ numericvar_to_int64(const NumericVar *var, int64 *result)
weight = rounded.weight; weight = rounded.weight;
Assert(weight >= 0 && ndigits <= weight + 1); 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; digits = rounded.digits;
neg = (rounded.sign == NUMERIC_NEG); neg = (rounded.sign == NUMERIC_NEG);
val = digits[0]; val = -digits[0];
for (i = 1; i <= weight; i++) for (i = 1; i <= weight; i++)
{ {
oldval = val; if (unlikely(pg_mul_s64_overflow(val, NBASE, &val)))
val *= NBASE; {
if (i < ndigits) free_var(&rounded);
val += digits[i]; return false;
}
/* if (i < ndigits)
* 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 (!neg || (-val) != val || val == 0 || oldval < 0) if (unlikely(pg_sub_s64_overflow(val, digits[i], &val)))
{ {
free_var(&rounded); free_var(&rounded);
return false; return false;
...@@ -6226,7 +6224,14 @@ numericvar_to_int64(const NumericVar *var, int64 *result) ...@@ -6226,7 +6224,14 @@ numericvar_to_int64(const NumericVar *var, int64 *result)
free_var(&rounded); free_var(&rounded);
*result = neg ? -val : val; if (!neg)
{
if (unlikely(val == INT64_MIN))
return false;
val = -val;
}
*result = val;
return true; return true;
} }
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
*/ */
#include "postgres.h" #include "postgres.h"
#include "common/int.h"
#include "utils/builtins.h" #include "utils/builtins.h"
#include "utils/formatting.h" #include "utils/formatting.h"
#include "mb/pg_wchar.h" #include "mb/pg_wchar.h"
...@@ -1045,19 +1046,12 @@ repeat(PG_FUNCTION_ARGS) ...@@ -1045,19 +1046,12 @@ repeat(PG_FUNCTION_ARGS)
count = 0; count = 0;
slen = VARSIZE_ANY_EXHDR(string); slen = VARSIZE_ANY_EXHDR(string);
tlen = VARHDRSZ + (count * slen);
/* Check for integer overflow */ if (unlikely(pg_mul_s32_overflow(count, slen, &tlen)) ||
if (slen != 0 && count != 0) unlikely(pg_add_s32_overflow(tlen, VARHDRSZ, &tlen)))
{
int check = count * slen;
int check2 = check + VARHDRSZ;
if ((check / slen) != count || check2 <= check)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg("requested length too large"))); errmsg("requested length too large")));
}
result = (text *) palloc(tlen); result = (text *) palloc(tlen);
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include "postgres.h" #include "postgres.h"
#include "access/htup_details.h" #include "access/htup_details.h"
#include "common/int.h"
#include "libpq/pqformat.h" #include "libpq/pqformat.h"
#include "nodes/nodeFuncs.h" #include "nodes/nodeFuncs.h"
#include "utils/array.h" #include "utils/array.h"
...@@ -1166,8 +1167,7 @@ bit_overlay(VarBit *t1, VarBit *t2, int sp, int sl) ...@@ -1166,8 +1167,7 @@ bit_overlay(VarBit *t1, VarBit *t2, int sp, int sl)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_SUBSTRING_ERROR), (errcode(ERRCODE_SUBSTRING_ERROR),
errmsg("negative substring length not allowed"))); errmsg("negative substring length not allowed")));
sp_pl_sl = sp + sl; if (pg_add_s32_overflow(sp, sl, &sp_pl_sl))
if (sp_pl_sl <= sl)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer out of range"))); errmsg("integer out of range")));
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include "access/tuptoaster.h" #include "access/tuptoaster.h"
#include "catalog/pg_collation.h" #include "catalog/pg_collation.h"
#include "catalog/pg_type.h" #include "catalog/pg_type.h"
#include "common/int.h"
#include "common/md5.h" #include "common/md5.h"
#include "lib/hyperloglog.h" #include "lib/hyperloglog.h"
#include "libpq/pqformat.h" #include "libpq/pqformat.h"
...@@ -1047,8 +1048,7 @@ text_overlay(text *t1, text *t2, int sp, int sl) ...@@ -1047,8 +1048,7 @@ text_overlay(text *t1, text *t2, int sp, int sl)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_SUBSTRING_ERROR), (errcode(ERRCODE_SUBSTRING_ERROR),
errmsg("negative substring length not allowed"))); errmsg("negative substring length not allowed")));
sp_pl_sl = sp + sl; if (pg_add_s32_overflow(sp, sl, &sp_pl_sl))
if (sp_pl_sl <= sl)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer out of range"))); errmsg("integer out of range")));
...@@ -2950,8 +2950,7 @@ bytea_overlay(bytea *t1, bytea *t2, int sp, int sl) ...@@ -2950,8 +2950,7 @@ bytea_overlay(bytea *t1, bytea *t2, int sp, int sl)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_SUBSTRING_ERROR), (errcode(ERRCODE_SUBSTRING_ERROR),
errmsg("negative substring length not allowed"))); errmsg("negative substring length not allowed")));
sp_pl_sl = sp + sl; if (pg_add_s32_overflow(sp, sl, &sp_pl_sl))
if (sp_pl_sl <= sl)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer 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) ...@@ -5279,13 +5278,13 @@ text_format_parse_digits(const char **ptr, const char *end_ptr, int *value)
while (*cp >= '0' && *cp <= '9') 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, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("number is out of range"))); errmsg("number is out of range")));
val = newval;
ADVANCE_PARSE_POINTER(cp, end_ptr); ADVANCE_PARSE_POINTER(cp, end_ptr);
found = true; found = true;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment