@@ -671,18 +671,6 @@ int4mul(PG_FUNCTION_ARGS)
671671 int32 arg2 = PG_GETARG_INT32 (1 );
672672 int32 result ;
673673
674- #ifdef WIN32
675-
676- /*
677- * Win32 doesn't throw a catchable exception for SELECT -2147483648 *
678- * (-1); -- INT_MIN
679- */
680- if (arg2 == -1 && arg1 == INT_MIN )
681- ereport (ERROR ,
682- (errcode (ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE ),
683- errmsg ("integer out of range" )));
684- #endif
685-
686674 result = arg1 * arg2 ;
687675
688676 /*
@@ -699,7 +687,8 @@ int4mul(PG_FUNCTION_ARGS)
699687 if (!(arg1 >= (int32 ) SHRT_MIN && arg1 <= (int32 ) SHRT_MAX &&
700688 arg2 >= (int32 ) SHRT_MIN && arg2 <= (int32 ) SHRT_MAX ) &&
701689 arg2 != 0 &&
702- (result / arg2 != arg1 || (arg2 == -1 && arg1 < 0 && result < 0 )))
690+ ((arg2 == -1 && arg1 < 0 && result < 0 ) ||
691+ result / arg2 != arg1 ))
703692 ereport (ERROR ,
704693 (errcode (ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE ),
705694 errmsg ("integer out of range" )));
@@ -722,29 +711,27 @@ int4div(PG_FUNCTION_ARGS)
722711 PG_RETURN_NULL ();
723712 }
724713
725- #ifdef WIN32
726-
727714 /*
728- * Win32 doesn't throw a catchable exception for SELECT -2147483648 /
729- * (-1); -- INT_MIN
715+ * INT_MIN / -1 is problematic, since the result can't be represented on a
716+ * two's-complement machine. Some machines produce INT_MIN, some produce
717+ * zero, some throw an exception. We can dodge the problem by recognizing
718+ * that division by -1 is the same as negation.
730719 */
731- if (arg2 == -1 && arg1 == INT_MIN )
732- ereport (ERROR ,
733- (errcode (ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE ),
734- errmsg ("integer out of range" )));
735- #endif
720+ if (arg2 == -1 )
721+ {
722+ result = - arg1 ;
723+ /* overflow check (needed for INT_MIN) */
724+ if (arg1 != 0 && SAMESIGN (result , arg1 ))
725+ ereport (ERROR ,
726+ (errcode (ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE ),
727+ errmsg ("integer out of range" )));
728+ PG_RETURN_INT32 (result );
729+ }
730+
731+ /* No overflow is possible */
736732
737733 result = arg1 / arg2 ;
738734
739- /*
740- * Overflow check. The only possible overflow case is for arg1 = INT_MIN,
741- * arg2 = -1, where the correct result is -INT_MIN, which can't be
742- * represented on a two's-complement machine.
743- */
744- if (arg2 == -1 && arg1 < 0 && result < 0 )
745- ereport (ERROR ,
746- (errcode (ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE ),
747- errmsg ("integer out of range" )));
748735 PG_RETURN_INT32 (result );
749736}
750737
@@ -866,17 +853,27 @@ int2div(PG_FUNCTION_ARGS)
866853 PG_RETURN_NULL ();
867854 }
868855
869- result = arg1 / arg2 ;
870-
871856 /*
872- * Overflow check. The only possible overflow case is for arg1 =
873- * SHRT_MIN, arg2 = -1, where the correct result is -SHRT_MIN, which can't
874- * be represented on a two's-complement machine.
857+ * SHRT_MIN / -1 is problematic, since the result can't be represented on
858+ * a two's-complement machine. Some machines produce SHRT_MIN, some
859+ * produce zero, some throw an exception. We can dodge the problem by
860+ * recognizing that division by -1 is the same as negation.
875861 */
876- if (arg2 == -1 && arg1 < 0 && result < 0 )
877- ereport (ERROR ,
878- (errcode (ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE ),
879- errmsg ("smallint out of range" )));
862+ if (arg2 == -1 )
863+ {
864+ result = - arg1 ;
865+ /* overflow check (needed for SHRT_MIN) */
866+ if (arg1 != 0 && SAMESIGN (result , arg1 ))
867+ ereport (ERROR ,
868+ (errcode (ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE ),
869+ errmsg ("smallint out of range" )));
870+ PG_RETURN_INT16 (result );
871+ }
872+
873+ /* No overflow is possible */
874+
875+ result = arg1 / arg2 ;
876+
880877 PG_RETURN_INT16 (result );
881878}
882879
@@ -1054,17 +1051,27 @@ int42div(PG_FUNCTION_ARGS)
10541051 PG_RETURN_NULL ();
10551052 }
10561053
1057- result = arg1 / arg2 ;
1058-
10591054 /*
1060- * Overflow check. The only possible overflow case is for arg1 = INT_MIN,
1061- * arg2 = -1, where the correct result is -INT_MIN, which can't be
1062- * represented on a two's-complement machine.
1055+ * INT_MIN / -1 is problematic, since the result can't be represented on a
1056+ * two's-complement machine. Some machines produce INT_MIN, some produce
1057+ * zero, some throw an exception. We can dodge the problem by recognizing
1058+ * that division by -1 is the same as negation.
10631059 */
1064- if (arg2 == -1 && arg1 < 0 && result < 0 )
1065- ereport (ERROR ,
1066- (errcode (ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE ),
1067- errmsg ("integer out of range" )));
1060+ if (arg2 == -1 )
1061+ {
1062+ result = - arg1 ;
1063+ /* overflow check (needed for INT_MIN) */
1064+ if (arg1 != 0 && SAMESIGN (result , arg1 ))
1065+ ereport (ERROR ,
1066+ (errcode (ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE ),
1067+ errmsg ("integer out of range" )));
1068+ PG_RETURN_INT32 (result );
1069+ }
1070+
1071+ /* No overflow is possible */
1072+
1073+ result = arg1 / arg2 ;
1074+
10681075 PG_RETURN_INT32 (result );
10691076}
10701077
@@ -1160,6 +1167,14 @@ int42mod(PG_FUNCTION_ARGS)
11601167 PG_RETURN_NULL ();
11611168 }
11621169
1170+ /*
1171+ * Some machines throw a floating-point exception for INT_MIN % -1, which
1172+ * is a bit silly since the correct answer is perfectly well-defined,
1173+ * namely zero.
1174+ */
1175+ if (arg2 == -1 )
1176+ PG_RETURN_INT32 (0 );
1177+
11631178 /* No overflow is possible */
11641179
11651180 PG_RETURN_INT32 (arg1 % arg2 );
0 commit comments