int32 arg2 = PG_GETARG_INT32(1);
int32 result;
-#ifdef WIN32
-
- /*
- * Win32 doesn't throw a catchable exception for SELECT -2147483648 *
- * (-1); -- INT_MIN
- */
- if (arg2 == -1 && arg1 == INT_MIN)
- ereport(ERROR,
- (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
- errmsg("integer out of range")));
-#endif
-
result = arg1 * arg2;
/*
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)))
+ ((arg2 == -1 && arg1 < 0 && result < 0) ||
+ result / arg2 != arg1))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer out of range")));
PG_RETURN_NULL();
}
-#ifdef WIN32
-
/*
- * Win32 doesn't throw a catchable exception for SELECT -2147483648 /
- * (-1); -- INT_MIN
+ * INT_MIN / -1 is problematic, since the result can't be represented on a
+ * two's-complement machine. Some machines produce INT_MIN, some produce
+ * zero, some throw an exception. We can dodge the problem by recognizing
+ * that division by -1 is the same as negation.
*/
- if (arg2 == -1 && arg1 == INT_MIN)
- ereport(ERROR,
- (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
- errmsg("integer out of range")));
-#endif
+ if (arg2 == -1)
+ {
+ result = -arg1;
+ /* overflow check (needed for INT_MIN) */
+ if (arg1 != 0 && SAMESIGN(result, arg1))
+ ereport(ERROR,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("integer out of range")));
+ PG_RETURN_INT32(result);
+ }
+
+ /* No overflow is possible */
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);
}
PG_RETURN_NULL();
}
- 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.
+ * SHRT_MIN / -1 is problematic, since the result can't be represented on
+ * a two's-complement machine. Some machines produce SHRT_MIN, some
+ * produce zero, some throw an exception. We can dodge the problem by
+ * recognizing that division by -1 is the same as negation.
*/
- if (arg2 == -1 && arg1 < 0 && result < 0)
- ereport(ERROR,
- (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
- errmsg("smallint out of range")));
+ if (arg2 == -1)
+ {
+ result = -arg1;
+ /* overflow check (needed for SHRT_MIN) */
+ if (arg1 != 0 && SAMESIGN(result, arg1))
+ ereport(ERROR,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("smallint out of range")));
+ PG_RETURN_INT16(result);
+ }
+
+ /* No overflow is possible */
+
+ result = arg1 / arg2;
+
PG_RETURN_INT16(result);
}
PG_RETURN_NULL();
}
- 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.
+ * INT_MIN / -1 is problematic, since the result can't be represented on a
+ * two's-complement machine. Some machines produce INT_MIN, some produce
+ * zero, some throw an exception. We can dodge the problem by recognizing
+ * that division by -1 is the same as negation.
*/
- if (arg2 == -1 && arg1 < 0 && result < 0)
- ereport(ERROR,
- (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
- errmsg("integer out of range")));
+ if (arg2 == -1)
+ {
+ result = -arg1;
+ /* overflow check (needed for INT_MIN) */
+ if (arg1 != 0 && SAMESIGN(result, arg1))
+ ereport(ERROR,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("integer out of range")));
+ PG_RETURN_INT32(result);
+ }
+
+ /* No overflow is possible */
+
+ result = arg1 / arg2;
+
PG_RETURN_INT32(result);
}
PG_RETURN_NULL();
}
+ /*
+ * Some machines throw a floating-point exception for INT_MIN % -1, which
+ * is a bit silly since the correct answer is perfectly well-defined,
+ * namely zero.
+ */
+ if (arg2 == -1)
+ PG_RETURN_INT32(0);
+
/* No overflow is possible */
PG_RETURN_INT32(arg1 % arg2);
#endif
{
if (arg2 != 0 &&
- (result / arg2 != arg1 || (arg2 == -1 && arg1 < 0 && result < 0)))
+ ((arg2 == -1 && arg1 < 0 && result < 0) ||
+ result / arg2 != arg1))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("bigint out of range")));
PG_RETURN_NULL();
}
- 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.
+ * INT64_MIN / -1 is problematic, since the result can't be represented on
+ * a two's-complement machine. Some machines produce INT64_MIN, some
+ * produce zero, some throw an exception. We can dodge the problem by
+ * recognizing that division by -1 is the same as negation.
*/
- if (arg2 == -1 && arg1 < 0 && result < 0)
- ereport(ERROR,
- (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
- errmsg("bigint out of range")));
+ if (arg2 == -1)
+ {
+ result = -arg1;
+ /* overflow check (needed for INT64_MIN) */
+ if (arg1 != 0 && SAMESIGN(result, arg1))
+ ereport(ERROR,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("bigint out of range")));
+ PG_RETURN_INT64(result);
+ }
+
+ /* No overflow is possible */
+
+ result = arg1 / arg2;
+
PG_RETURN_INT64(result);
}
PG_RETURN_NULL();
}
- 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.
+ * INT64_MIN / -1 is problematic, since the result can't be represented on
+ * a two's-complement machine. Some machines produce INT64_MIN, some
+ * produce zero, some throw an exception. We can dodge the problem by
+ * recognizing that division by -1 is the same as negation.
*/
- if (arg2 == -1 && arg1 < 0 && result < 0)
- ereport(ERROR,
- (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
- errmsg("bigint out of range")));
+ if (arg2 == -1)
+ {
+ result = -arg1;
+ /* overflow check (needed for INT64_MIN) */
+ if (arg1 != 0 && SAMESIGN(result, arg1))
+ ereport(ERROR,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("bigint out of range")));
+ PG_RETURN_INT64(result);
+ }
+
+ /* No overflow is possible */
+
+ result = arg1 / arg2;
+
PG_RETURN_INT64(result);
}
| -32767 | -16383
(5 rows)
+-- check sane handling of INT16_MIN overflow cases
+SELECT (-32768)::int2 * (-1)::int2;
+ERROR: smallint out of range
+SELECT (-32768)::int2 / (-1)::int2;
+ERROR: smallint out of range
+SELECT (-32768)::int2 % (-1)::int2;
+ ?column?
+----------
+ 0
+(1 row)
+
2
(1 row)
+-- check sane handling of INT_MIN overflow cases
+SELECT (-2147483648)::int4 * (-1)::int4;
+ERROR: integer out of range
+SELECT (-2147483648)::int4 / (-1)::int4;
+ERROR: integer out of range
+SELECT (-2147483648)::int4 % (-1)::int4;
+ ?column?
+----------
+ 0
+(1 row)
+
+SELECT (-2147483648)::int4 * (-1)::int2;
+ERROR: integer out of range
+SELECT (-2147483648)::int4 / (-1)::int2;
+ERROR: integer out of range
+SELECT (-2147483648)::int4 % (-1)::int2;
+ ?column?
+----------
+ 0
+(1 row)
+
select '9223372036854775808'::int8;
ERROR: value "9223372036854775808" is out of range for type bigint
+-- check sane handling of INT64_MIN overflow cases
+SELECT (-9223372036854775808)::int8 * (-1)::int8;
+ERROR: bigint out of range
+SELECT (-9223372036854775808)::int8 / (-1)::int8;
+ERROR: bigint out of range
+SELECT (-9223372036854775808)::int8 % (-1)::int8;
+ ?column?
+----------
+ 0
+(1 row)
+
+SELECT (-9223372036854775808)::int8 * (-1)::int4;
+ERROR: bigint out of range
+SELECT (-9223372036854775808)::int8 / (-1)::int4;
+ERROR: bigint out of range
+SELECT (-9223372036854775808)::int8 % (-1)::int4;
+ ?column?
+----------
+ 0
+(1 row)
+
select '9223372036854775808'::int8;
ERROR: value "9223372036854775808" is out of range for type bigint
+-- check sane handling of INT64_MIN overflow cases
+SELECT (-9223372036854775808)::int8 * (-1)::int8;
+ERROR: bigint out of range
+SELECT (-9223372036854775808)::int8 / (-1)::int8;
+ERROR: bigint out of range
+SELECT (-9223372036854775808)::int8 % (-1)::int8;
+ ?column?
+----------
+ 0
+(1 row)
+
+SELECT (-9223372036854775808)::int8 * (-1)::int4;
+ERROR: bigint out of range
+SELECT (-9223372036854775808)::int8 / (-1)::int4;
+ERROR: bigint out of range
+SELECT (-9223372036854775808)::int8 % (-1)::int4;
+ ?column?
+----------
+ 0
+(1 row)
+
SELECT '' AS five, i.f1, i.f1 / int4 '2' AS x FROM INT2_TBL i;
+-- check sane handling of INT16_MIN overflow cases
+SELECT (-32768)::int2 * (-1)::int2;
+SELECT (-32768)::int2 / (-1)::int2;
+SELECT (-32768)::int2 % (-1)::int2;
SELECT 2 + 2 / 2 AS three;
SELECT (2 + 2) / 2 AS two;
+
+-- check sane handling of INT_MIN overflow cases
+SELECT (-2147483648)::int4 * (-1)::int4;
+SELECT (-2147483648)::int4 / (-1)::int4;
+SELECT (-2147483648)::int4 % (-1)::int4;
+SELECT (-2147483648)::int4 * (-1)::int2;
+SELECT (-2147483648)::int4 / (-1)::int2;
+SELECT (-2147483648)::int4 % (-1)::int2;
select '-9223372036854775809'::int8;
select '9223372036854775807'::int8;
select '9223372036854775808'::int8;
+
+-- check sane handling of INT64_MIN overflow cases
+SELECT (-9223372036854775808)::int8 * (-1)::int8;
+SELECT (-9223372036854775808)::int8 / (-1)::int8;
+SELECT (-9223372036854775808)::int8 % (-1)::int8;
+SELECT (-9223372036854775808)::int8 * (-1)::int4;
+SELECT (-9223372036854775808)::int8 / (-1)::int4;
+SELECT (-9223372036854775808)::int8 % (-1)::int4;