bigint variants). Clean up some inconsistencies in error message wording.
Fix scanint8 to allow trailing whitespace in INT64_MIN case. Update
int8-exp-three-digits.out, which seems to have been ignored by the last
couple of people to modify the int8 regression test, and remove
int8-exp-three-digits-win32.out which is thereby exposed as redundant.
+
+ Overflow in integer arithmetic operations is now detected and
+ reported as an error.
+
+
+
The server now warns of empty strings passed to
+
+ Overflow in integer arithmetic operations is now detected (Tom)
+
+
+
Syntax checking of array input values considerably tightened up (Joe)
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/adt/float.c,v 1.110 2004/09/02 17:12:50 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/float.c,v 1.111 2004/10/04 14:42:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
if ((num < SHRT_MIN) || (num > SHRT_MAX))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
- errmsg("integer out of range")));
+ errmsg("smallint out of range")));
result = (int16) rint(num);
PG_RETURN_INT16(result);
if ((num < SHRT_MIN) || (num > SHRT_MAX))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
- errmsg("integer out of range")));
+ errmsg("smallint out of range")));
result = (int16) rint(num);
PG_RETURN_INT16(result);
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/adt/int.c,v 1.62 2004/08/29 05:06:49 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/int.c,v 1.63 2004/10/04 14:42:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
* Arithmetic operators:
* intmod
*/
-
#include "postgres.h"
#include
#include "libpq/pqformat.h"
#include "utils/builtins.h"
+
#ifndef SHRT_MAX
#define SHRT_MAX (0x7FFF)
#endif
#define SHRT_MIN (-0x8000)
#endif
+#define SAMESIGN(a,b) (((a) < 0) == ((b) < 0))
+
typedef struct
{
int32 current;
int32 step;
} generate_series_fctx;
+
/*****************************************************************************
* USER I/O ROUTINES *
*****************************************************************************/
if (arg1 < SHRT_MIN || arg1 > SHRT_MAX)
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
- errmsg("integer out of range")));
+ errmsg("smallint out of range")));
PG_RETURN_INT16((int16) arg1);
}
int4um(PG_FUNCTION_ARGS)
{
int32 arg = PG_GETARG_INT32(0);
+ int32 result;
- PG_RETURN_INT32(-arg);
+ result = -arg;
+ /* overflow check (needed for INT_MIN) */
+ if (arg != 0 && SAMESIGN(result, arg))
+ ereport(ERROR,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("integer out of range")));
+ PG_RETURN_INT32(result);
}
Datum
{
int32 arg1 = PG_GETARG_INT32(0);
int32 arg2 = PG_GETARG_INT32(1);
+ int32 result;
- PG_RETURN_INT32(arg1 + arg2);
+ 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))
+ ereport(ERROR,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("integer out of range")));
+ PG_RETURN_INT32(result);
}
Datum
{
int32 arg1 = PG_GETARG_INT32(0);
int32 arg2 = PG_GETARG_INT32(1);
+ int32 result;
- PG_RETURN_INT32(arg1 - arg2);
+ 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))
+ ereport(ERROR,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("integer out of range")));
+ PG_RETURN_INT32(result);
}
Datum
{
int32 arg1 = PG_GETARG_INT32(0);
int32 arg2 = PG_GETARG_INT32(1);
+ int32 result;
- PG_RETURN_INT32(arg1 * arg2);
+ 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 &&
+ (result/arg2 != arg1 || (arg2 == -1 && arg1 < 0 && result < 0)))
+ ereport(ERROR,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("integer out of range")));
+ PG_RETURN_INT32(result);
}
Datum
{
int32 arg1 = PG_GETARG_INT32(0);
int32 arg2 = PG_GETARG_INT32(1);
+ int32 result;
if (arg2 == 0)
ereport(ERROR,
(errcode(ERRCODE_DIVISION_BY_ZERO),
errmsg("division by zero")));
- PG_RETURN_INT32(arg1 / arg2);
+ result = arg1 / arg2;
+ /*
+ * Overflow check. The only possible overflow case is for
+ * arg1 = INT_MIN, arg2 = -1, where the correct result is -INT_MIN,
+ * which can't be represented on a two's-complement machine.
+ */
+ if (arg2 == -1 && arg1 < 0 && result < 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("integer out of range")));
+ PG_RETURN_INT32(result);
}
Datum
int4inc(PG_FUNCTION_ARGS)
{
int32 arg = PG_GETARG_INT32(0);
+ int32 result;
- PG_RETURN_INT32(arg + 1);
+ result = arg + 1;
+ /* Overflow check */
+ if (arg > 0 && result < 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("integer out of range")));
+
+ PG_RETURN_INT32(result);
}
Datum
int2um(PG_FUNCTION_ARGS)
{
int16 arg = PG_GETARG_INT16(0);
+ int16 result;
- PG_RETURN_INT16(-arg);
+ result = -arg;
+ /* overflow check (needed for SHRT_MIN) */
+ if (arg != 0 && SAMESIGN(result, arg))
+ ereport(ERROR,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("smallint out of range")));
+ PG_RETURN_INT16(result);
}
Datum
{
int16 arg1 = PG_GETARG_INT16(0);
int16 arg2 = PG_GETARG_INT16(1);
+ int16 result;
- PG_RETURN_INT16(arg1 + arg2);
+ 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))
+ ereport(ERROR,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("smallint out of range")));
+ PG_RETURN_INT16(result);
}
Datum
{
int16 arg1 = PG_GETARG_INT16(0);
int16 arg2 = PG_GETARG_INT16(1);
+ int16 result;
- PG_RETURN_INT16(arg1 - arg2);
+ 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))
+ ereport(ERROR,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("smallint out of range")));
+ PG_RETURN_INT16(result);
}
Datum
{
int16 arg1 = PG_GETARG_INT16(0);
int16 arg2 = PG_GETARG_INT16(1);
+ int32 result32;
- PG_RETURN_INT16(arg1 * arg2);
+ /*
+ * 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)
+ ereport(ERROR,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("smallint out of range")));
+
+ PG_RETURN_INT16((int16) result32);
}
Datum
{
int16 arg1 = PG_GETARG_INT16(0);
int16 arg2 = PG_GETARG_INT16(1);
+ int16 result;
if (arg2 == 0)
ereport(ERROR,
(errcode(ERRCODE_DIVISION_BY_ZERO),
errmsg("division by zero")));
- PG_RETURN_INT16(arg1 / arg2);
+ result = arg1 / arg2;
+ /*
+ * Overflow check. The only possible overflow case is for
+ * arg1 = SHRT_MIN, arg2 = -1, where the correct result is -SHRT_MIN,
+ * which can't be represented on a two's-complement machine.
+ */
+ if (arg2 == -1 && arg1 < 0 && result < 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("smallint out of range")));
+ PG_RETURN_INT16(result);
}
Datum
{
int16 arg1 = PG_GETARG_INT16(0);
int32 arg2 = PG_GETARG_INT32(1);
+ int32 result;
- PG_RETURN_INT32(arg1 + arg2);
+ 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))
+ ereport(ERROR,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("integer out of range")));
+ PG_RETURN_INT32(result);
}
Datum
{
int16 arg1 = PG_GETARG_INT16(0);
int32 arg2 = PG_GETARG_INT32(1);
+ int32 result;
- PG_RETURN_INT32(arg1 - arg2);
+ 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))
+ ereport(ERROR,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("integer out of range")));
+ PG_RETURN_INT32(result);
}
Datum
{
int16 arg1 = PG_GETARG_INT16(0);
int32 arg2 = PG_GETARG_INT32(1);
+ int32 result;
- PG_RETURN_INT32(arg1 * arg2);
+ 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)
+ ereport(ERROR,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("integer out of range")));
+ PG_RETURN_INT32(result);
}
Datum
ereport(ERROR,
(errcode(ERRCODE_DIVISION_BY_ZERO),
errmsg("division by zero")));
-
- PG_RETURN_INT32(arg1 / arg2);
+ /* No overflow is possible */
+ PG_RETURN_INT32((int32) arg1 / arg2);
}
Datum
{
int32 arg1 = PG_GETARG_INT32(0);
int16 arg2 = PG_GETARG_INT16(1);
+ int32 result;
- PG_RETURN_INT32(arg1 + arg2);
+ 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))
+ ereport(ERROR,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("integer out of range")));
+ PG_RETURN_INT32(result);
}
Datum
{
int32 arg1 = PG_GETARG_INT32(0);
int16 arg2 = PG_GETARG_INT16(1);
+ int32 result;
- PG_RETURN_INT32(arg1 - arg2);
+ 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))
+ ereport(ERROR,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("integer out of range")));
+ PG_RETURN_INT32(result);
}
Datum
{
int32 arg1 = PG_GETARG_INT32(0);
int16 arg2 = PG_GETARG_INT16(1);
+ int32 result;
- PG_RETURN_INT32(arg1 * arg2);
+ 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)
+ ereport(ERROR,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("integer out of range")));
+ PG_RETURN_INT32(result);
}
Datum
{
int32 arg1 = PG_GETARG_INT32(0);
int16 arg2 = PG_GETARG_INT16(1);
+ int32 result;
if (arg2 == 0)
ereport(ERROR,
(errcode(ERRCODE_DIVISION_BY_ZERO),
errmsg("division by zero")));
- PG_RETURN_INT32(arg1 / arg2);
+ result = arg1 / arg2;
+ /*
+ * Overflow check. The only possible overflow case is for
+ * arg1 = INT_MIN, arg2 = -1, where the correct result is -INT_MIN,
+ * which can't be represented on a two's-complement machine.
+ */
+ if (arg2 == -1 && arg1 < 0 && result < 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("integer out of range")));
+ PG_RETURN_INT32(result);
}
Datum
ereport(ERROR,
(errcode(ERRCODE_DIVISION_BY_ZERO),
errmsg("division by zero")));
+ /* No overflow is possible */
PG_RETURN_INT32(arg1 % arg2);
}
ereport(ERROR,
(errcode(ERRCODE_DIVISION_BY_ZERO),
errmsg("division by zero")));
+ /* No overflow is possible */
PG_RETURN_INT16(arg1 % arg2);
}
ereport(ERROR,
(errcode(ERRCODE_DIVISION_BY_ZERO),
errmsg("division by zero")));
+ /* No overflow is possible */
PG_RETURN_INT32(arg1 % arg2);
}
ereport(ERROR,
(errcode(ERRCODE_DIVISION_BY_ZERO),
errmsg("division by zero")));
+ /* No overflow is possible */
PG_RETURN_INT32(arg1 % arg2);
}
int4abs(PG_FUNCTION_ARGS)
{
int32 arg1 = PG_GETARG_INT32(0);
+ int32 result;
- PG_RETURN_INT32((arg1 < 0) ? -arg1 : arg1);
+ result = (arg1 < 0) ? -arg1 : arg1;
+ /* overflow check (needed for INT_MIN) */
+ if (result < 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("integer out of range")));
+ PG_RETURN_INT32(result);
}
Datum
int2abs(PG_FUNCTION_ARGS)
{
int16 arg1 = PG_GETARG_INT16(0);
+ int16 result;
- PG_RETURN_INT16((arg1 < 0) ? -arg1 : arg1);
+ result = (arg1 < 0) ? -arg1 : arg1;
+ /* overflow check (needed for SHRT_MIN) */
+ if (result < 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("smallint out of range")));
+ PG_RETURN_INT16(result);
}
Datum
PG_RETURN_INT32((arg1 < arg2) ? arg1 : arg2);
}
-/* Binary arithmetics
+/*
+ * Bit-pushing operators
*
* int[24]and - returns arg1 & arg2
* int[24]or - returns arg1 | arg2
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/adt/int8.c,v 1.55 2004/08/29 05:06:49 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/int8.c,v 1.56 2004/10/04 14:42:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#define MAXINT8LEN 25
+#define SAMESIGN(a,b) (((a) < 0) == ((b) < 0))
+
typedef struct
{
int64 current;
int64 step;
} generate_series_fctx;
+
/***********************************************************************
**
** Routines for 64-bit integers.
if (*ptr == '-')
{
ptr++;
- sign = -1;
/*
* Do an explicit check for INT64_MIN. Ugly though this is, it's
* portably.
*/
#ifndef INT64_IS_BUSTED
- if (strcmp(ptr, "9223372036854775808") == 0)
+ if (strncmp(ptr, "9223372036854775808", 19) == 0)
{
- *result = -INT64CONST(0x7fffffffffffffff) - 1;
- return true;
+ tmp = -INT64CONST(0x7fffffffffffffff) - 1;
+ ptr += 19;
+ goto gotdigits;
}
#endif
+
+ sign = -1;
}
else if (*ptr == '+')
ptr++;
else
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
- errmsg("invalid input syntax for type bigint: \"%s\"", str)));
+ errmsg("invalid input syntax for integer: \"%s\"",
+ str)));
}
/* process digits */
else
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
- errmsg("integer out of range")));
+ errmsg("value \"%s\" is out of range for type bigint",
+ str)));
}
tmp = newtmp;
}
+gotdigits:
+
/* allow trailing whitespace, but not other trailing chars */
while (*ptr != '\0' && isspace((unsigned char) *ptr))
ptr++;
else
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
- errmsg("invalid input syntax for type bigint: \"%s\"", str)));
+ errmsg("invalid input syntax for integer: \"%s\"",
+ str)));
}
*result = (sign < 0) ? -tmp : tmp;
Datum
int8um(PG_FUNCTION_ARGS)
{
- int64 val = PG_GETARG_INT64(0);
+ int64 arg = PG_GETARG_INT64(0);
+ int64 result;
- PG_RETURN_INT64(-val);
+ result = -arg;
+ /* overflow check (needed for INT64_MIN) */
+ if (arg != 0 && SAMESIGN(result, arg))
+ ereport(ERROR,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("bigint out of range")));
+ PG_RETURN_INT64(result);
}
Datum
int8up(PG_FUNCTION_ARGS)
{
- int64 val = PG_GETARG_INT64(0);
+ int64 arg = PG_GETARG_INT64(0);
- PG_RETURN_INT64(val);
+ PG_RETURN_INT64(arg);
}
Datum
int8pl(PG_FUNCTION_ARGS)
{
- int64 val1 = PG_GETARG_INT64(0);
- int64 val2 = PG_GETARG_INT64(1);
+ int64 arg1 = PG_GETARG_INT64(0);
+ int64 arg2 = PG_GETARG_INT64(1);
+ int64 result;
- PG_RETURN_INT64(val1 + val2);
+ 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))
+ ereport(ERROR,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("bigint out of range")));
+ PG_RETURN_INT64(result);
}
Datum
int8mi(PG_FUNCTION_ARGS)
{
- int64 val1 = PG_GETARG_INT64(0);
- int64 val2 = PG_GETARG_INT64(1);
+ int64 arg1 = PG_GETARG_INT64(0);
+ int64 arg2 = PG_GETARG_INT64(1);
+ int64 result;
- PG_RETURN_INT64(val1 - val2);
+ 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))
+ ereport(ERROR,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("bigint out of range")));
+ PG_RETURN_INT64(result);
}
Datum
int8mul(PG_FUNCTION_ARGS)
{
- int64 val1 = PG_GETARG_INT64(0);
- int64 val2 = PG_GETARG_INT64(1);
+ int64 arg1 = PG_GETARG_INT64(0);
+ int64 arg2 = PG_GETARG_INT64(1);
+ int64 result;
- PG_RETURN_INT64(val1 * val2);
+ 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)) &&
+ arg2 != 0 &&
+ (result/arg2 != arg1 || (arg2 == -1 && arg1 < 0 && result < 0)))
+ ereport(ERROR,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("bigint out of range")));
+ PG_RETURN_INT64(result);
}
Datum
int8div(PG_FUNCTION_ARGS)
{
- int64 val1 = PG_GETARG_INT64(0);
- int64 val2 = PG_GETARG_INT64(1);
+ int64 arg1 = PG_GETARG_INT64(0);
+ int64 arg2 = PG_GETARG_INT64(1);
+ int64 result;
- if (val2 == 0)
+ if (arg2 == 0)
ereport(ERROR,
(errcode(ERRCODE_DIVISION_BY_ZERO),
errmsg("division by zero")));
- PG_RETURN_INT64(val1 / val2);
+ result = arg1 / arg2;
+ /*
+ * Overflow check. The only possible overflow case is for
+ * arg1 = INT64_MIN, arg2 = -1, where the correct result is -INT64_MIN,
+ * which can't be represented on a two's-complement machine.
+ */
+ if (arg2 == -1 && arg1 < 0 && result < 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("bigint out of range")));
+ PG_RETURN_INT64(result);
}
/* int8abs()
int8abs(PG_FUNCTION_ARGS)
{
int64 arg1 = PG_GETARG_INT64(0);
+ int64 result;
- PG_RETURN_INT64((arg1 < 0) ? -arg1 : arg1);
+ result = (arg1 < 0) ? -arg1 : arg1;
+ /* overflow check (needed for INT64_MIN) */
+ if (result < 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("bigint out of range")));
+ PG_RETURN_INT64(result);
}
/* int8mod()
Datum
int8mod(PG_FUNCTION_ARGS)
{
- int64 val1 = PG_GETARG_INT64(0);
- int64 val2 = PG_GETARG_INT64(1);
- int64 result;
+ int64 arg1 = PG_GETARG_INT64(0);
+ int64 arg2 = PG_GETARG_INT64(1);
- if (val2 == 0)
+ if (arg2 == 0)
ereport(ERROR,
(errcode(ERRCODE_DIVISION_BY_ZERO),
errmsg("division by zero")));
+ /* No overflow is possible */
- result = val1 / val2;
- result *= val2;
- result = val1 - result;
-
- PG_RETURN_INT64(result);
+ PG_RETURN_INT64(arg1 % arg2);
}
int8inc(PG_FUNCTION_ARGS)
{
int64 arg = PG_GETARG_INT64(0);
+ int64 result;
- PG_RETURN_INT64(arg + 1);
+ result = arg + 1;
+ /* Overflow check */
+ if (arg > 0 && result < 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("bigint out of range")));
+
+ PG_RETURN_INT64(result);
}
Datum
int8larger(PG_FUNCTION_ARGS)
{
- int64 val1 = PG_GETARG_INT64(0);
- int64 val2 = PG_GETARG_INT64(1);
+ int64 arg1 = PG_GETARG_INT64(0);
+ int64 arg2 = PG_GETARG_INT64(1);
int64 result;
- result = ((val1 > val2) ? val1 : val2);
+ result = ((arg1 > arg2) ? arg1 : arg2);
PG_RETURN_INT64(result);
}
Datum
int8smaller(PG_FUNCTION_ARGS)
{
- int64 val1 = PG_GETARG_INT64(0);
- int64 val2 = PG_GETARG_INT64(1);
+ int64 arg1 = PG_GETARG_INT64(0);
+ int64 arg2 = PG_GETARG_INT64(1);
int64 result;
- result = ((val1 < val2) ? val1 : val2);
+ result = ((arg1 < arg2) ? arg1 : arg2);
PG_RETURN_INT64(result);
}
Datum
int84pl(PG_FUNCTION_ARGS)
{
- int64 val1 = PG_GETARG_INT64(0);
- int32 val2 = PG_GETARG_INT32(1);
+ int64 arg1 = PG_GETARG_INT64(0);
+ int32 arg2 = PG_GETARG_INT32(1);
+ int64 result;
- PG_RETURN_INT64(val1 + val2);
+ 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))
+ ereport(ERROR,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("bigint out of range")));
+ PG_RETURN_INT64(result);
}
Datum
int84mi(PG_FUNCTION_ARGS)
{
- int64 val1 = PG_GETARG_INT64(0);
- int32 val2 = PG_GETARG_INT32(1);
+ int64 arg1 = PG_GETARG_INT64(0);
+ int32 arg2 = PG_GETARG_INT32(1);
+ int64 result;
- PG_RETURN_INT64(val1 - val2);
+ 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))
+ ereport(ERROR,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("bigint out of range")));
+ PG_RETURN_INT64(result);
}
Datum
int84mul(PG_FUNCTION_ARGS)
{
- int64 val1 = PG_GETARG_INT64(0);
- int32 val2 = PG_GETARG_INT32(1);
+ int64 arg1 = PG_GETARG_INT64(0);
+ int32 arg2 = PG_GETARG_INT32(1);
+ int64 result;
- PG_RETURN_INT64(val1 * val2);
+ 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)
+ ereport(ERROR,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("bigint out of range")));
+ PG_RETURN_INT64(result);
}
Datum
int84div(PG_FUNCTION_ARGS)
{
- int64 val1 = PG_GETARG_INT64(0);
- int32 val2 = PG_GETARG_INT32(1);
+ int64 arg1 = PG_GETARG_INT64(0);
+ int32 arg2 = PG_GETARG_INT32(1);
+ int64 result;
- if (val2 == 0)
+ if (arg2 == 0)
ereport(ERROR,
(errcode(ERRCODE_DIVISION_BY_ZERO),
errmsg("division by zero")));
- PG_RETURN_INT64(val1 / val2);
+ result = arg1 / arg2;
+ /*
+ * Overflow check. The only possible overflow case is for
+ * arg1 = INT64_MIN, arg2 = -1, where the correct result is -INT64_MIN,
+ * which can't be represented on a two's-complement machine.
+ */
+ if (arg2 == -1 && arg1 < 0 && result < 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("bigint out of range")));
+ PG_RETURN_INT64(result);
}
Datum
int48pl(PG_FUNCTION_ARGS)
{
- int32 val1 = PG_GETARG_INT32(0);
- int64 val2 = PG_GETARG_INT64(1);
+ int32 arg1 = PG_GETARG_INT32(0);
+ int64 arg2 = PG_GETARG_INT64(1);
+ int64 result;
- PG_RETURN_INT64(val1 + val2);
+ 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))
+ ereport(ERROR,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("bigint out of range")));
+ PG_RETURN_INT64(result);
}
Datum
int48mi(PG_FUNCTION_ARGS)
{
- int32 val1 = PG_GETARG_INT32(0);
- int64 val2 = PG_GETARG_INT64(1);
+ int32 arg1 = PG_GETARG_INT32(0);
+ int64 arg2 = PG_GETARG_INT64(1);
+ int64 result;
- PG_RETURN_INT64(val1 - val2);
+ 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))
+ ereport(ERROR,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("bigint out of range")));
+ PG_RETURN_INT64(result);
}
Datum
int48mul(PG_FUNCTION_ARGS)
{
- int32 val1 = PG_GETARG_INT32(0);
- int64 val2 = PG_GETARG_INT64(1);
+ int32 arg1 = PG_GETARG_INT32(0);
+ int64 arg2 = PG_GETARG_INT64(1);
+ int64 result;
- PG_RETURN_INT64(val1 * val2);
+ 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)
+ ereport(ERROR,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("bigint out of range")));
+ PG_RETURN_INT64(result);
}
Datum
int48div(PG_FUNCTION_ARGS)
{
- int32 val1 = PG_GETARG_INT32(0);
- int64 val2 = PG_GETARG_INT64(1);
+ int32 arg1 = PG_GETARG_INT32(0);
+ int64 arg2 = PG_GETARG_INT64(1);
- if (val2 == 0)
+ if (arg2 == 0)
ereport(ERROR,
(errcode(ERRCODE_DIVISION_BY_ZERO),
errmsg("division by zero")));
-
- PG_RETURN_INT64(val1 / val2);
+ /* No overflow is possible */
+ PG_RETURN_INT64((int64) arg1 / arg2);
}
/* Binary arithmetics
Datum
int48(PG_FUNCTION_ARGS)
{
- int32 val = PG_GETARG_INT32(0);
+ int32 arg = PG_GETARG_INT32(0);
- PG_RETURN_INT64((int64) val);
+ PG_RETURN_INT64((int64) arg);
}
Datum
int84(PG_FUNCTION_ARGS)
{
- int64 val = PG_GETARG_INT64(0);
+ int64 arg = PG_GETARG_INT64(0);
int32 result;
- result = (int32) val;
+ result = (int32) arg;
/* Test for overflow by reverse-conversion. */
- if ((int64) result != val)
+ if ((int64) result != arg)
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer out of range")));
Datum
int28(PG_FUNCTION_ARGS)
{
- int16 val = PG_GETARG_INT16(0);
+ int16 arg = PG_GETARG_INT16(0);
- PG_RETURN_INT64((int64) val);
+ PG_RETURN_INT64((int64) arg);
}
Datum
int82(PG_FUNCTION_ARGS)
{
- int64 val = PG_GETARG_INT64(0);
+ int64 arg = PG_GETARG_INT64(0);
int16 result;
- result = (int16) val;
+ result = (int16) arg;
/* Test for overflow by reverse-conversion. */
- if ((int64) result != val)
+ if ((int64) result != arg)
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
- errmsg("integer out of range")));
+ errmsg("smallint out of range")));
PG_RETURN_INT16(result);
}
Datum
i8tod(PG_FUNCTION_ARGS)
{
- int64 val = PG_GETARG_INT64(0);
+ int64 arg = PG_GETARG_INT64(0);
float8 result;
- result = val;
+ result = arg;
PG_RETURN_FLOAT8(result);
}
Datum
dtoi8(PG_FUNCTION_ARGS)
{
- float8 val = PG_GETARG_FLOAT8(0);
+ float8 arg = PG_GETARG_FLOAT8(0);
int64 result;
- /* Round val to nearest integer (but it's still in float form) */
- val = rint(val);
+ /* 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) val;
+ result = (int64) arg;
- if ((float8) result != val)
+ if ((float8) result != arg)
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
- errmsg("integer out of range")));
+ errmsg("bigint out of range")));
PG_RETURN_INT64(result);
}
Datum
i8tof(PG_FUNCTION_ARGS)
{
- int64 val = PG_GETARG_INT64(0);
+ int64 arg = PG_GETARG_INT64(0);
float4 result;
- result = val;
+ result = arg;
PG_RETURN_FLOAT4(result);
}
Datum
ftoi8(PG_FUNCTION_ARGS)
{
- float4 val = PG_GETARG_FLOAT4(0);
+ float4 arg = PG_GETARG_FLOAT4(0);
int64 result;
- float8 dval;
+ float8 darg;
- /* Round val to nearest integer (but it's still in float form) */
- dval = rint(val);
+ /* 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) dval;
+ result = (int64) darg;
- if ((float8) result != dval)
+ if ((float8) result != darg)
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
- errmsg("integer out of range")));
+ errmsg("bigint out of range")));
PG_RETURN_INT64(result);
}
Datum
i8tooid(PG_FUNCTION_ARGS)
{
- int64 val = PG_GETARG_INT64(0);
+ int64 arg = PG_GETARG_INT64(0);
Oid result;
- result = (Oid) val;
+ result = (Oid) arg;
/* Test for overflow by reverse-conversion. */
- if ((int64) result != val)
+ if ((int64) result != arg)
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("OID out of range")));
Datum
oidtoi8(PG_FUNCTION_ARGS)
{
- Oid val = PG_GETARG_OID(0);
+ Oid arg = PG_GETARG_OID(0);
- PG_RETURN_INT64((int64) val);
+ PG_RETURN_INT64((int64) arg);
}
Datum
Datum
int8_text(PG_FUNCTION_ARGS)
{
- /* val is int64, but easier to leave it as Datum */
- Datum val = PG_GETARG_DATUM(0);
+ /* arg is int64, but easier to leave it as Datum */
+ Datum arg = PG_GETARG_DATUM(0);
char *s;
int len;
text *result;
- s = DatumGetCString(DirectFunctionCall1(int8out, val));
+ s = DatumGetCString(DirectFunctionCall1(int8out, arg));
len = strlen(s);
result = (text *) palloc(VARHDRSZ + len);
* Copyright (c) 1998-2004, PostgreSQL Global Development Group
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/adt/numeric.c,v 1.79 2004/08/30 02:54:39 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/numeric.c,v 1.80 2004/10/04 14:42:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
if (NUMERIC_IS_NAN(num))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("cannot convert NaN to integer")));
+ errmsg("cannot convert NaN to bigint")));
/* Convert to variable format and thence to int8 */
init_var(&x);
if (!numericvar_to_int8(&x, &result))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
- errmsg("integer out of range")));
+ errmsg("bigint out of range")));
free_var(&x);
if (NUMERIC_IS_NAN(num))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("cannot convert NaN to integer")));
+ errmsg("cannot convert NaN to smallint")));
/* Convert to variable format and thence to int8 */
init_var(&x);
if (!numericvar_to_int8(&x, &val))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
- errmsg("integer out of range")));
+ errmsg("smallint out of range")));
free_var(&x);
if ((int64) result != val)
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
- errmsg("integer out of range")));
+ errmsg("smallint out of range")));
PG_RETURN_INT16(result);
}
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/adt/numutils.c,v 1.65 2004/08/29 05:06:49 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/numutils.c,v 1.66 2004/10/04 14:42:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
if (errno == ERANGE || l < SHRT_MIN || l > SHRT_MAX)
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
- errmsg("value \"%s\" is out of range for type shortint", s)));
+ errmsg("value \"%s\" is out of range for type smallint", s)));
break;
case sizeof(int8):
if (errno == ERANGE || l < SCHAR_MIN || l > SCHAR_MAX)
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/adt/varbit.c,v 1.42 2004/08/29 05:06:49 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/varbit.c,v 1.43 2004/10/04 14:42:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
if (VARBITLEN(arg) > sizeof(result) * BITS_PER_BYTE)
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
- errmsg("integer out of range")));
+ errmsg("bigint out of range")));
result = 0;
for (r = VARBITS(arg); r < VARBITEND(arg); r++)
INSERT INTO INT2_TBL(f1) VALUES ('-32767');
-- bad input values -- should give errors
INSERT INTO INT2_TBL(f1) VALUES ('100000');
-ERROR: value "100000" is out of range for type shortint
+ERROR: value "100000" is out of range for type smallint
INSERT INTO INT2_TBL(f1) VALUES ('asdf');
ERROR: invalid input syntax for integer: "asdf"
INSERT INTO INT2_TBL(f1) VALUES (' ');
(3 rows)
SELECT '' AS five, i.f1, i.f1 * int2 '2' AS x FROM INT2_TBL i;
- five | f1 | x
-------+--------+-------
- | 0 | 0
- | 1234 | 2468
- | -1234 | -2468
- | 32767 | -2
- | -32767 | 2
-(5 rows)
+ERROR: smallint out of range
+SELECT '' AS five, i.f1, i.f1 * int2 '2' AS x FROM INT2_TBL i
+WHERE abs(f1) < 16384;
+ five | f1 | x
+------+-------+-------
+ | 0 | 0
+ | 1234 | 2468
+ | -1234 | -2468
+(3 rows)
SELECT '' AS five, i.f1, i.f1 * int4 '2' AS x FROM INT2_TBL i;
five | f1 | x
(5 rows)
SELECT '' AS five, i.f1, i.f1 + int2 '2' AS x FROM INT2_TBL i;
+ERROR: smallint out of range
+SELECT '' AS five, i.f1, i.f1 + int2 '2' AS x FROM INT2_TBL i
+WHERE f1 < 32766;
five | f1 | x
------+--------+--------
| 0 | 2
| 1234 | 1236
| -1234 | -1232
- | 32767 | -32767
| -32767 | -32765
-(5 rows)
+(4 rows)
SELECT '' AS five, i.f1, i.f1 + int4 '2' AS x FROM INT2_TBL i;
five | f1 | x
(5 rows)
SELECT '' AS five, i.f1, i.f1 - int2 '2' AS x FROM INT2_TBL i;
- five | f1 | x
-------+--------+-------
- | 0 | -2
- | 1234 | 1232
- | -1234 | -1236
- | 32767 | 32765
- | -32767 | 32767
-(5 rows)
+ERROR: smallint out of range
+SELECT '' AS five, i.f1, i.f1 - int2 '2' AS x FROM INT2_TBL i
+WHERE f1 > -32767;
+ five | f1 | x
+------+-------+-------
+ | 0 | -2
+ | 1234 | 1232
+ | -1234 | -1236
+ | 32767 | 32765
+(4 rows)
SELECT '' AS five, i.f1, i.f1 - int4 '2' AS x FROM INT2_TBL i;
five | f1 | x
(3 rows)
SELECT '' AS five, i.f1, i.f1 * int2 '2' AS x FROM INT4_TBL i;
- five | f1 | x
-------+-------------+---------
- | 0 | 0
- | 123456 | 246912
- | -123456 | -246912
- | 2147483647 | -2
- | -2147483647 | 2
-(5 rows)
+ERROR: integer out of range
+SELECT '' AS five, i.f1, i.f1 * int2 '2' AS x FROM INT4_TBL i
+WHERE abs(f1) < 1073741824;
+ five | f1 | x
+------+---------+---------
+ | 0 | 0
+ | 123456 | 246912
+ | -123456 | -246912
+(3 rows)
SELECT '' AS five, i.f1, i.f1 * int4 '2' AS x FROM INT4_TBL i;
- five | f1 | x
-------+-------------+---------
- | 0 | 0
- | 123456 | 246912
- | -123456 | -246912
- | 2147483647 | -2
- | -2147483647 | 2
-(5 rows)
+ERROR: integer out of range
+SELECT '' AS five, i.f1, i.f1 * int4 '2' AS x FROM INT4_TBL i
+WHERE abs(f1) < 1073741824;
+ five | f1 | x
+------+---------+---------
+ | 0 | 0
+ | 123456 | 246912
+ | -123456 | -246912
+(3 rows)
SELECT '' AS five, i.f1, i.f1 + int2 '2' AS x FROM INT4_TBL i;
+ERROR: integer out of range
+SELECT '' AS five, i.f1, i.f1 + int2 '2' AS x FROM INT4_TBL i
+WHERE f1 < 2147483646;
five | f1 | x
------+-------------+-------------
| 0 | 2
| 123456 | 123458
| -123456 | -123454
- | 2147483647 | -2147483647
| -2147483647 | -2147483645
-(5 rows)
+(4 rows)
SELECT '' AS five, i.f1, i.f1 + int4 '2' AS x FROM INT4_TBL i;
+ERROR: integer out of range
+SELECT '' AS five, i.f1, i.f1 + int4 '2' AS x FROM INT4_TBL i
+WHERE f1 < 2147483646;
five | f1 | x
------+-------------+-------------
| 0 | 2
| 123456 | 123458
| -123456 | -123454
- | 2147483647 | -2147483647
| -2147483647 | -2147483645
-(5 rows)
+(4 rows)
SELECT '' AS five, i.f1, i.f1 - int2 '2' AS x FROM INT4_TBL i;
- five | f1 | x
-------+-------------+------------
- | 0 | -2
- | 123456 | 123454
- | -123456 | -123458
- | 2147483647 | 2147483645
- | -2147483647 | 2147483647
-(5 rows)
+ERROR: integer out of range
+SELECT '' AS five, i.f1, i.f1 - int2 '2' AS x FROM INT4_TBL i
+WHERE f1 > -2147483647;
+ five | f1 | x
+------+------------+------------
+ | 0 | -2
+ | 123456 | 123454
+ | -123456 | -123458
+ | 2147483647 | 2147483645
+(4 rows)
SELECT '' AS five, i.f1, i.f1 - int4 '2' AS x FROM INT4_TBL i;
- five | f1 | x
-------+-------------+------------
- | 0 | -2
- | 123456 | 123454
- | -123456 | -123458
- | 2147483647 | 2147483645
- | -2147483647 | 2147483647
-(5 rows)
+ERROR: integer out of range
+SELECT '' AS five, i.f1, i.f1 - int4 '2' AS x FROM INT4_TBL i
+WHERE f1 > -2147483647;
+ five | f1 | x
+------+------------+------------
+ | 0 | -2
+ | 123456 | 123454
+ | -123456 | -123458
+ | 2147483647 | 2147483645
+(4 rows)
SELECT '' AS five, i.f1, i.f1 / int2 '2' AS x FROM INT4_TBL i;
five | f1 | x
+++ /dev/null
---
--- INT8
--- Test int8 64-bit integers.
---
-CREATE TABLE INT8_TBL(q1 int8, q2 int8);
-INSERT INTO INT8_TBL VALUES('123','456');
-INSERT INTO INT8_TBL VALUES('123','4567890123456789');
-INSERT INTO INT8_TBL VALUES('4567890123456789','123');
-INSERT INTO INT8_TBL VALUES('4567890123456789','4567890123456789');
-INSERT INTO INT8_TBL VALUES('4567890123456789','-4567890123456789');
--- bad inputs
-INSERT INTO INT8_TBL(q1) VALUES (' ');
-ERROR: invalid input syntax for type bigint: " "
-INSERT INTO INT8_TBL(q1) VALUES ('xxx');
-ERROR: invalid input syntax for type bigint: "xxx"
-INSERT INTO INT8_TBL(q1) VALUES ('3908203590239580293850293850329485');
-ERROR: integer out of range
-INSERT INTO INT8_TBL(q1) VALUES ('-1204982019841029840928340329840934');
-ERROR: integer out of range
-INSERT INTO INT8_TBL(q1) VALUES ('- 123');
-ERROR: invalid input syntax for type bigint: "- 123"
-INSERT INTO INT8_TBL(q1) VALUES (' 345 5');
-ERROR: invalid input syntax for type bigint: " 345 5"
-INSERT INTO INT8_TBL(q1) VALUES ('');
-ERROR: invalid input syntax for type bigint: ""
-SELECT * FROM INT8_TBL;
- q1 | q2
-------------------+-------------------
- 123 | 456
- 123 | 4567890123456789
- 4567890123456789 | 123
- 4567890123456789 | 4567890123456789
- 4567890123456789 | -4567890123456789
-(5 rows)
-
-SELECT '' AS five, q1 AS plus, -q1 AS minus FROM INT8_TBL;
- five | plus | minus
-------+------------------+-------------------
- | 123 | -123
- | 123 | -123
- | 4567890123456789 | -4567890123456789
- | 4567890123456789 | -4567890123456789
- | 4567890123456789 | -4567890123456789
-(5 rows)
-
-SELECT '' AS five, q1, q2, q1 + q2 AS plus FROM INT8_TBL;
- five | q1 | q2 | plus
-------+------------------+-------------------+------------------
- | 123 | 456 | 579
- | 123 | 4567890123456789 | 4567890123456912
- | 4567890123456789 | 123 | 4567890123456912
- | 4567890123456789 | 4567890123456789 | 9135780246913578
- | 4567890123456789 | -4567890123456789 | 0
-(5 rows)
-
-SELECT '' AS five, q1, q2, q1 - q2 AS minus FROM INT8_TBL;
- five | q1 | q2 | minus
-------+------------------+-------------------+-------------------
- | 123 | 456 | -333
- | 123 | 4567890123456789 | -4567890123456666
- | 4567890123456789 | 123 | 4567890123456666
- | 4567890123456789 | 4567890123456789 | 0
- | 4567890123456789 | -4567890123456789 | 9135780246913578
-(5 rows)
-
-SELECT '' AS three, q1, q2, q1 * q2 AS multiply FROM INT8_TBL
- WHERE q1 < 1000 or (q2 > 0 and q2 < 1000);
- three | q1 | q2 | multiply
--------+------------------+------------------+--------------------
- | 123 | 456 | 56088
- | 123 | 4567890123456789 | 561850485185185047
- | 4567890123456789 | 123 | 561850485185185047
-(3 rows)
-
-SELECT '' AS five, q1, q2, q1 / q2 AS divide FROM INT8_TBL;
- five | q1 | q2 | divide
-------+------------------+-------------------+----------------
- | 123 | 456 | 0
- | 123 | 4567890123456789 | 0
- | 4567890123456789 | 123 | 37137318076884
- | 4567890123456789 | 4567890123456789 | 1
- | 4567890123456789 | -4567890123456789 | -1
-(5 rows)
-
-SELECT '' AS five, q1, float8(q1) FROM INT8_TBL;
- five | q1 | float8
-------+------------------+-----------------------
- | 123 | 123
- | 123 | 123
- | 4567890123456789 | 4.56789012345679e+015
- | 4567890123456789 | 4.56789012345679e+015
- | 4567890123456789 | 4.56789012345679e+015
-(5 rows)
-
-SELECT '' AS five, q2, float8(q2) FROM INT8_TBL;
- five | q2 | float8
-------+-------------------+------------------------
- | 456 | 456
- | 4567890123456789 | 4.56789012345679e+015
- | 123 | 123
- | 4567890123456789 | 4.56789012345679e+015
- | -4567890123456789 | -4.56789012345679e+015
-(5 rows)
-
-SELECT '' AS five, 2 * q1 AS "twice int4" FROM INT8_TBL;
- five | twice int4
-------+------------------
- | 246
- | 246
- | 9135780246913578
- | 9135780246913578
- | 9135780246913578
-(5 rows)
-
-SELECT '' AS five, q1 * 2 AS "twice int4" FROM INT8_TBL;
- five | twice int4
-------+------------------
- | 246
- | 246
- | 9135780246913578
- | 9135780246913578
- | 9135780246913578
-(5 rows)
-
--- TO_CHAR()
---
-SELECT '' AS to_char_1, to_char(q1, '9G999G999G999G999G999'), to_char(q2, '9,999,999,999,999,999')
- FROM INT8_TBL;
- to_char_1 | to_char | to_char
------------+------------------------+------------------------
- | 123 | 456
- | 123 | 4,567,890,123,456,789
- | 4,567,890,123,456,789 | 123
- | 4,567,890,123,456,789 | 4,567,890,123,456,789
- | 4,567,890,123,456,789 | -4,567,890,123,456,789
-(5 rows)
-
-SELECT '' AS to_char_2, to_char(q1, '9G999G999G999G999G999D999G999'), to_char(q2, '9,999,999,999,999,999.999,999')
- FROM INT8_TBL;
- to_char_2 | to_char | to_char
------------+--------------------------------+--------------------------------
- | 123.000,000 | 456.000,000
- | 123.000,000 | 4,567,890,123,456,789.000,000
- | 4,567,890,123,456,789.000,000 | 123.000,000
- | 4,567,890,123,456,789.000,000 | 4,567,890,123,456,789.000,000
- | 4,567,890,123,456,789.000,000 | -4,567,890,123,456,789.000,000
-(5 rows)
-
-SELECT '' AS to_char_3, to_char( (q1 * -1), '9999999999999999PR'), to_char( (q2 * -1), '9999999999999999.999PR')
- FROM INT8_TBL;
- to_char_3 | to_char | to_char
------------+--------------------+------------------------
- | <123> | <456.000>
- | <123> | <4567890123456789.000>
- | <4567890123456789> | <123.000>
- | <4567890123456789> | <4567890123456789.000>
- | <4567890123456789> | 4567890123456789.000
-(5 rows)
-
-SELECT '' AS to_char_4, to_char( (q1 * -1), '9999999999999999S'), to_char( (q2 * -1), 'S9999999999999999')
- FROM INT8_TBL;
- to_char_4 | to_char | to_char
------------+-------------------+-------------------
- | 123- | -456
- | 123- | -4567890123456789
- | 4567890123456789- | -123
- | 4567890123456789- | -4567890123456789
- | 4567890123456789- | +4567890123456789
-(5 rows)
-
-SELECT '' AS to_char_5, to_char(q2, 'MI9999999999999999') FROM INT8_TBL;
- to_char_5 | to_char
------------+-------------------
- | 456
- | 4567890123456789
- | 123
- | 4567890123456789
- | -4567890123456789
-(5 rows)
-
-SELECT '' AS to_char_6, to_char(q2, 'FMS9999999999999999') FROM INT8_TBL;
- to_char_6 | to_char
------------+-------------------
- | +456
- | +4567890123456789
- | +123
- | +4567890123456789
- | -4567890123456789
-(5 rows)
-
-SELECT '' AS to_char_7, to_char(q2, 'FM9999999999999999THPR') FROM INT8_TBL;
- to_char_7 | to_char
------------+--------------------
- | 456TH
- | 4567890123456789TH
- | 123RD
- | 4567890123456789TH
- | <4567890123456789>
-(5 rows)
-
-SELECT '' AS to_char_8, to_char(q2, 'SG9999999999999999th') FROM INT8_TBL;
- to_char_8 | to_char
------------+---------------------
- | + 456th
- | +4567890123456789th
- | + 123rd
- | +4567890123456789th
- | -4567890123456789
-(5 rows)
-
-SELECT '' AS to_char_9, to_char(q2, '0999999999999999') FROM INT8_TBL;
- to_char_9 | to_char
------------+-------------------
- | 0000000000000456
- | 4567890123456789
- | 0000000000000123
- | 4567890123456789
- | -4567890123456789
-(5 rows)
-
-SELECT '' AS to_char_10, to_char(q2, 'S0999999999999999') FROM INT8_TBL;
- to_char_10 | to_char
-------------+-------------------
- | +0000000000000456
- | +4567890123456789
- | +0000000000000123
- | +4567890123456789
- | -4567890123456789
-(5 rows)
-
-SELECT '' AS to_char_11, to_char(q2, 'FM0999999999999999') FROM INT8_TBL;
- to_char_11 | to_char
-------------+-------------------
- | 0000000000000456
- | 4567890123456789
- | 0000000000000123
- | 4567890123456789
- | -4567890123456789
-(5 rows)
-
-SELECT '' AS to_char_12, to_char(q2, 'FM9999999999999999.000') FROM INT8_TBL;
- to_char_12 | to_char
-------------+-----------------------
- | 456.000
- | 4567890123456789.000
- | 123.000
- | 4567890123456789.000
- | -4567890123456789.000
-(5 rows)
-
-SELECT '' AS to_char_13, to_char(q2, 'L9999999999999999.000') FROM INT8_TBL;
- to_char_13 | to_char
-------------+------------------------
- | 456.000
- | 4567890123456789.000
- | 123.000
- | 4567890123456789.000
- | -4567890123456789.000
-(5 rows)
-
-SELECT '' AS to_char_14, to_char(q2, 'FM9999999999999999.999') FROM INT8_TBL;
- to_char_14 | to_char
-------------+--------------------
- | 456.
- | 4567890123456789.
- | 123.
- | 4567890123456789.
- | -4567890123456789.
-(5 rows)
-
-SELECT '' AS to_char_15, to_char(q2, 'S 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 . 9 9 9') FROM INT8_TBL;
- to_char_15 | to_char
-------------+-------------------------------------------
- | +4 5 6 . 0 0 0
- | +4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 . 0 0 0
- | +1 2 3 . 0 0 0
- | +4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 . 0 0 0
- | -4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 . 0 0 0
-(5 rows)
-
-SELECT '' AS to_char_16, to_char(q2, '99999 "text" 9999 "9999" 999 "\\"text between quote marks\\"" 9999') FROM INT8_TBL;
- to_char_16 | to_char
-------------+-----------------------------------------------------------
- | text 9999 "text between quote marks" 456
- | 45678 text 9012 9999 345 "text between quote marks" 6789
- | text 9999 "text between quote marks" 123
- | 45678 text 9012 9999 345 "text between quote marks" 6789
- | -45678 text 9012 9999 345 "text between quote marks" 6789
-(5 rows)
-
-SELECT '' AS to_char_17, to_char(q2, '999999SG9999999999') FROM INT8_TBL;
- to_char_17 | to_char
-------------+-------------------
- | + 456
- | 456789+0123456789
- | + 123
- | 456789+0123456789
- | 456789-0123456789
-(5 rows)
-
-- Test int8 64-bit integers.
--
CREATE TABLE INT8_TBL(q1 int8, q2 int8);
-INSERT INTO INT8_TBL VALUES('123','456');
-INSERT INTO INT8_TBL VALUES('123','4567890123456789');
+INSERT INTO INT8_TBL VALUES(' 123 ',' 456');
+INSERT INTO INT8_TBL VALUES('123 ','4567890123456789');
INSERT INTO INT8_TBL VALUES('4567890123456789','123');
INSERT INTO INT8_TBL VALUES('4567890123456789','4567890123456789');
INSERT INTO INT8_TBL VALUES('4567890123456789','-4567890123456789');
+-- bad inputs
+INSERT INTO INT8_TBL(q1) VALUES (' ');
+ERROR: invalid input syntax for integer: " "
+INSERT INTO INT8_TBL(q1) VALUES ('xxx');
+ERROR: invalid input syntax for integer: "xxx"
+INSERT INTO INT8_TBL(q1) VALUES ('3908203590239580293850293850329485');
+ERROR: value "3908203590239580293850293850329485" is out of range for type bigint
+INSERT INTO INT8_TBL(q1) VALUES ('-1204982019841029840928340329840934');
+ERROR: value "-1204982019841029840928340329840934" is out of range for type bigint
+INSERT INTO INT8_TBL(q1) VALUES ('- 123');
+ERROR: invalid input syntax for integer: "- 123"
+INSERT INTO INT8_TBL(q1) VALUES (' 345 5');
+ERROR: invalid input syntax for integer: " 345 5"
+INSERT INTO INT8_TBL(q1) VALUES ('');
+ERROR: invalid input syntax for integer: ""
SELECT * FROM INT8_TBL;
q1 | q2
------------------+-------------------
| 4567890123456789 | -4567890123456789 | 9135780246913578
(5 rows)
+SELECT '' AS three, q1, q2, q1 * q2 AS multiply FROM INT8_TBL;
+ERROR: bigint out of range
SELECT '' AS three, q1, q2, q1 * q2 AS multiply FROM INT8_TBL
WHERE q1 < 1000 or (q2 > 0 and q2 < 1000);
three | q1 | q2 | multiply
| <123> | <4567890123456789.000>
| <4567890123456789> | <123.000>
| <4567890123456789> | <4567890123456789.000>
- | <4567890123456789> | 4567890123456789.000
+ | <4567890123456789> | 4567890123456789.000
(5 rows)
SELECT '' AS to_char_4, to_char( (q1 * -1), '9999999999999999S'), to_char( (q2 * -1), 'S9999999999999999')
(5 rows)
SELECT '' AS to_char_5, to_char(q2, 'MI9999999999999999') FROM INT8_TBL;
- to_char_5 | to_char
------------+--------------------
- | 456
- | 4567890123456789
- | 123
- | 4567890123456789
+ to_char_5 | to_char
+-----------+-------------------
+ | 456
+ | 4567890123456789
+ | 123
+ | 4567890123456789
| -4567890123456789
(5 rows)
SELECT '' AS to_char_15, to_char(q2, 'S 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 . 9 9 9') FROM INT8_TBL;
to_char_15 | to_char
------------+-------------------------------------------
- | +4 5 6 . 0 0 0
- | + 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 . 0 0 0
- | +1 2 3 . 0 0 0
- | + 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 . 0 0 0
- | - 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 . 0 0 0
+ | +4 5 6 . 0 0 0
+ | +4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 . 0 0 0
+ | +1 2 3 . 0 0 0
+ | +4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 . 0 0 0
+ | -4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 . 0 0 0
(5 rows)
SELECT '' AS to_char_16, to_char(q2, '99999 "text" 9999 "9999" 999 "\\"text between quote marks\\"" 9999') FROM INT8_TBL;
INSERT INTO INT8_TBL VALUES('4567890123456789','-4567890123456789');
-- bad inputs
INSERT INTO INT8_TBL(q1) VALUES (' ');
-ERROR: invalid input syntax for type bigint: " "
+ERROR: invalid input syntax for integer: " "
INSERT INTO INT8_TBL(q1) VALUES ('xxx');
-ERROR: invalid input syntax for type bigint: "xxx"
+ERROR: invalid input syntax for integer: "xxx"
INSERT INTO INT8_TBL(q1) VALUES ('3908203590239580293850293850329485');
-ERROR: integer out of range
+ERROR: value "3908203590239580293850293850329485" is out of range for type bigint
INSERT INTO INT8_TBL(q1) VALUES ('-1204982019841029840928340329840934');
-ERROR: integer out of range
+ERROR: value "-1204982019841029840928340329840934" is out of range for type bigint
INSERT INTO INT8_TBL(q1) VALUES ('- 123');
-ERROR: invalid input syntax for type bigint: "- 123"
+ERROR: invalid input syntax for integer: "- 123"
INSERT INTO INT8_TBL(q1) VALUES (' 345 5');
-ERROR: invalid input syntax for type bigint: " 345 5"
+ERROR: invalid input syntax for integer: " 345 5"
INSERT INTO INT8_TBL(q1) VALUES ('');
-ERROR: invalid input syntax for type bigint: ""
+ERROR: invalid input syntax for integer: ""
SELECT * FROM INT8_TBL;
q1 | q2
------------------+-------------------
| 4567890123456789 | -4567890123456789 | 9135780246913578
(5 rows)
+SELECT '' AS three, q1, q2, q1 * q2 AS multiply FROM INT8_TBL;
+ERROR: bigint out of range
SELECT '' AS three, q1, q2, q1 * q2 AS multiply FROM INT8_TBL
WHERE q1 < 1000 or (q2 > 0 and q2 < 1000);
three | q1 | q2 | multiply
--
SELECT '' AS eight, ss.f1 AS "Correlated Field", ss.f3 AS "Second Field"
FROM SUBSELECT_TBL ss
- WHERE f1 NOT IN (SELECT f1+1 FROM INT4_TBL WHERE f1 != ss.f1);
+ WHERE f1 NOT IN (SELECT f1+1 FROM INT4_TBL
+ WHERE f1 != ss.f1 AND f1 < 2147483647);
eight | Correlated Field | Second Field
-------+------------------+--------------
| 2 | 4
float8/i.86-pc-mingw32=float8-exp-three-digits-win32
float8/i.86-pc-cygwin=float8-small-is-zero
int8/.*-qnx=int8-exp-three-digits
-int8/i.86-pc-mingw32=int8-exp-three-digits-win32
+int8/i.86-pc-mingw32=int8-exp-three-digits
SELECT '' AS five, i.f1, i.f1 * int2 '2' AS x FROM INT2_TBL i;
+SELECT '' AS five, i.f1, i.f1 * int2 '2' AS x FROM INT2_TBL i
+WHERE abs(f1) < 16384;
+
SELECT '' AS five, i.f1, i.f1 * int4 '2' AS x FROM INT2_TBL i;
SELECT '' AS five, i.f1, i.f1 + int2 '2' AS x FROM INT2_TBL i;
+SELECT '' AS five, i.f1, i.f1 + int2 '2' AS x FROM INT2_TBL i
+WHERE f1 < 32766;
+
SELECT '' AS five, i.f1, i.f1 + int4 '2' AS x FROM INT2_TBL i;
SELECT '' AS five, i.f1, i.f1 - int2 '2' AS x FROM INT2_TBL i;
+SELECT '' AS five, i.f1, i.f1 - int2 '2' AS x FROM INT2_TBL i
+WHERE f1 > -32767;
+
SELECT '' AS five, i.f1, i.f1 - int4 '2' AS x FROM INT2_TBL i;
SELECT '' AS five, i.f1, i.f1 / int2 '2' AS x FROM INT2_TBL i;
SELECT '' AS five, i.f1, i.f1 * int2 '2' AS x FROM INT4_TBL i;
+SELECT '' AS five, i.f1, i.f1 * int2 '2' AS x FROM INT4_TBL i
+WHERE abs(f1) < 1073741824;
+
SELECT '' AS five, i.f1, i.f1 * int4 '2' AS x FROM INT4_TBL i;
+SELECT '' AS five, i.f1, i.f1 * int4 '2' AS x FROM INT4_TBL i
+WHERE abs(f1) < 1073741824;
+
SELECT '' AS five, i.f1, i.f1 + int2 '2' AS x FROM INT4_TBL i;
+SELECT '' AS five, i.f1, i.f1 + int2 '2' AS x FROM INT4_TBL i
+WHERE f1 < 2147483646;
+
SELECT '' AS five, i.f1, i.f1 + int4 '2' AS x FROM INT4_TBL i;
+SELECT '' AS five, i.f1, i.f1 + int4 '2' AS x FROM INT4_TBL i
+WHERE f1 < 2147483646;
+
SELECT '' AS five, i.f1, i.f1 - int2 '2' AS x FROM INT4_TBL i;
+SELECT '' AS five, i.f1, i.f1 - int2 '2' AS x FROM INT4_TBL i
+WHERE f1 > -2147483647;
+
SELECT '' AS five, i.f1, i.f1 - int4 '2' AS x FROM INT4_TBL i;
+SELECT '' AS five, i.f1, i.f1 - int4 '2' AS x FROM INT4_TBL i
+WHERE f1 > -2147483647;
+
SELECT '' AS five, i.f1, i.f1 / int2 '2' AS x FROM INT4_TBL i;
SELECT '' AS five, i.f1, i.f1 / int4 '2' AS x FROM INT4_TBL i;
SELECT '' AS five, q1, q2, q1 + q2 AS plus FROM INT8_TBL;
SELECT '' AS five, q1, q2, q1 - q2 AS minus FROM INT8_TBL;
+SELECT '' AS three, q1, q2, q1 * q2 AS multiply FROM INT8_TBL;
SELECT '' AS three, q1, q2, q1 * q2 AS multiply FROM INT8_TBL
WHERE q1 < 1000 or (q2 > 0 and q2 < 1000);
SELECT '' AS five, q1, q2, q1 / q2 AS divide FROM INT8_TBL;
SELECT '' AS eight, ss.f1 AS "Correlated Field", ss.f3 AS "Second Field"
FROM SUBSELECT_TBL ss
- WHERE f1 NOT IN (SELECT f1+1 FROM INT4_TBL WHERE f1 != ss.f1);
+ WHERE f1 NOT IN (SELECT f1+1 FROM INT4_TBL
+ WHERE f1 != ss.f1 AND f1 < 2147483647);
select q1, float8(count(*)) / (select count(*) from int8_tbl)
from int8_tbl group by q1 order by q1;