aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/adt/int.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/utils/adt/int.c')
-rw-r--r--src/backend/utils/adt/int.c200
1 files changed, 40 insertions, 160 deletions
diff --git a/src/backend/utils/adt/int.c b/src/backend/utils/adt/int.c
index 4cd8960b3fc..36ba86ca734 100644
--- a/src/backend/utils/adt/int.c
+++ b/src/backend/utils/adt/int.c
@@ -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;
-
- /*
- * 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;
+ int16 result;
- 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 */