diff options
Diffstat (limited to 'src/backend/utils/adt/float.c')
-rw-r--r-- | src/backend/utils/adt/float.c | 163 |
1 files changed, 120 insertions, 43 deletions
diff --git a/src/backend/utils/adt/float.c b/src/backend/utils/adt/float.c index a90d4db2150..012c3252f3c 100644 --- a/src/backend/utils/adt/float.c +++ b/src/backend/utils/adt/float.c @@ -87,6 +87,38 @@ static double cbrt(double x); /* + * We use these out-of-line ereport() calls to report float overflow, + * underflow, and zero-divide, because following our usual practice of + * repeating them at each call site would lead to a lot of code bloat. + * + * This does mean that you don't get a useful error location indicator. + */ +pg_noinline void +float_overflow_error(void) +{ + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("value out of range: overflow"))); +} + +pg_noinline void +float_underflow_error(void) +{ + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("value out of range: underflow"))); +} + +pg_noinline void +float_zero_divide_error(void) +{ + ereport(ERROR, + (errcode(ERRCODE_DIVISION_BY_ZERO), + errmsg("division by zero"))); +} + + +/* * Returns -1 if 'val' represents negative infinity, 1 if 'val' * represents (positive) infinity, and 0 otherwise. On some platforms, * this is equivalent to the isinf() macro, but not everywhere: C99 @@ -1190,10 +1222,15 @@ Datum dtof(PG_FUNCTION_ARGS) { float8 num = PG_GETARG_FLOAT8(0); + float4 result; - check_float4_val((float4) num, isinf(num), num == 0); + result = (float4) num; + if (unlikely(isinf(result)) && !isinf(num)) + float_overflow_error(); + if (unlikely(result == 0.0f) && num != 0.0) + float_underflow_error(); - PG_RETURN_FLOAT4((float4) num); + PG_RETURN_FLOAT4(result); } @@ -1444,8 +1481,11 @@ dsqrt(PG_FUNCTION_ARGS) errmsg("cannot take square root of a negative number"))); result = sqrt(arg1); + if (unlikely(isinf(result)) && !isinf(arg1)) + float_overflow_error(); + if (unlikely(result == 0.0) && arg1 != 0.0) + float_underflow_error(); - check_float8_val(result, isinf(arg1), arg1 == 0); PG_RETURN_FLOAT8(result); } @@ -1460,7 +1500,11 @@ dcbrt(PG_FUNCTION_ARGS) float8 result; result = cbrt(arg1); - check_float8_val(result, isinf(arg1), arg1 == 0); + if (unlikely(isinf(result)) && !isinf(arg1)) + float_overflow_error(); + if (unlikely(result == 0.0) && arg1 != 0.0) + float_underflow_error(); + PG_RETURN_FLOAT8(result); } @@ -1532,7 +1576,11 @@ dpow(PG_FUNCTION_ARGS) else if (errno == ERANGE && result != 0 && !isinf(result)) result = get_float8_infinity(); - check_float8_val(result, isinf(arg1) || isinf(arg2), arg1 == 0); + if (unlikely(isinf(result)) && !isinf(arg1) && !isinf(arg2)) + float_overflow_error(); + if (unlikely(result == 0.0) && arg1 != 0.0) + float_underflow_error(); + PG_RETURN_FLOAT8(result); } @@ -1551,7 +1599,11 @@ dexp(PG_FUNCTION_ARGS) if (errno == ERANGE && result != 0 && !isinf(result)) result = get_float8_infinity(); - check_float8_val(result, isinf(arg1), false); + if (unlikely(isinf(result)) && !isinf(arg1)) + float_overflow_error(); + if (unlikely(result == 0.0)) + float_underflow_error(); + PG_RETURN_FLOAT8(result); } @@ -1579,8 +1631,11 @@ dlog1(PG_FUNCTION_ARGS) errmsg("cannot take logarithm of a negative number"))); result = log(arg1); + if (unlikely(isinf(result)) && !isinf(arg1)) + float_overflow_error(); + if (unlikely(result == 0.0) && arg1 != 1.0) + float_underflow_error(); - check_float8_val(result, isinf(arg1), arg1 == 1); PG_RETURN_FLOAT8(result); } @@ -1609,8 +1664,11 @@ dlog10(PG_FUNCTION_ARGS) errmsg("cannot take logarithm of a negative number"))); result = log10(arg1); + if (unlikely(isinf(result)) && !isinf(arg1)) + float_overflow_error(); + if (unlikely(result == 0.0) && arg1 != 1.0) + float_underflow_error(); - check_float8_val(result, isinf(arg1), arg1 == 1); PG_RETURN_FLOAT8(result); } @@ -1639,8 +1697,9 @@ dacos(PG_FUNCTION_ARGS) errmsg("input is out of range"))); result = acos(arg1); + if (unlikely(isinf(result))) + float_overflow_error(); - check_float8_val(result, false, true); PG_RETURN_FLOAT8(result); } @@ -1669,8 +1728,9 @@ dasin(PG_FUNCTION_ARGS) errmsg("input is out of range"))); result = asin(arg1); + if (unlikely(isinf(result))) + float_overflow_error(); - check_float8_val(result, false, true); PG_RETURN_FLOAT8(result); } @@ -1694,8 +1754,9 @@ datan(PG_FUNCTION_ARGS) * finite, even if the input is infinite. */ result = atan(arg1); + if (unlikely(isinf(result))) + float_overflow_error(); - check_float8_val(result, false, true); PG_RETURN_FLOAT8(result); } @@ -1719,8 +1780,9 @@ datan2(PG_FUNCTION_ARGS) * should always be finite, even if the inputs are infinite. */ result = atan2(arg1, arg2); + if (unlikely(isinf(result))) + float_overflow_error(); - check_float8_val(result, false, true); PG_RETURN_FLOAT8(result); } @@ -1759,8 +1821,9 @@ dcos(PG_FUNCTION_ARGS) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("input is out of range"))); + if (unlikely(isinf(result))) + float_overflow_error(); - check_float8_val(result, false, true); PG_RETURN_FLOAT8(result); } @@ -1787,7 +1850,8 @@ dcot(PG_FUNCTION_ARGS) errmsg("input is out of range"))); result = 1.0 / result; - check_float8_val(result, true /* cot(0) == Inf */ , true); + /* Not checking for overflow because cot(0) == Inf */ + PG_RETURN_FLOAT8(result); } @@ -1812,8 +1876,9 @@ dsin(PG_FUNCTION_ARGS) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("input is out of range"))); + if (unlikely(isinf(result))) + float_overflow_error(); - check_float8_val(result, false, true); PG_RETURN_FLOAT8(result); } @@ -1838,8 +1903,8 @@ dtan(PG_FUNCTION_ARGS) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("input is out of range"))); + /* Not checking for overflow because tan(pi/2) == Inf */ - check_float8_val(result, true /* tan(pi/2) == Inf */ , true); PG_RETURN_FLOAT8(result); } @@ -1991,7 +2056,9 @@ dacosd(PG_FUNCTION_ARGS) else result = 90.0 + asind_q1(-arg1); - check_float8_val(result, false, true); + if (unlikely(isinf(result))) + float_overflow_error(); + PG_RETURN_FLOAT8(result); } @@ -2026,7 +2093,9 @@ dasind(PG_FUNCTION_ARGS) else result = -asind_q1(-arg1); - check_float8_val(result, false, true); + if (unlikely(isinf(result))) + float_overflow_error(); + PG_RETURN_FLOAT8(result); } @@ -2056,7 +2125,9 @@ datand(PG_FUNCTION_ARGS) atan_arg1 = atan(arg1); result = (atan_arg1 / atan_1_0) * 45.0; - check_float8_val(result, false, true); + if (unlikely(isinf(result))) + float_overflow_error(); + PG_RETURN_FLOAT8(result); } @@ -2090,7 +2161,9 @@ datan2d(PG_FUNCTION_ARGS) atan2_arg1_arg2 = atan2(arg1, arg2); result = (atan2_arg1_arg2 / atan_1_0) * 45.0; - check_float8_val(result, false, true); + if (unlikely(isinf(result))) + float_overflow_error(); + PG_RETURN_FLOAT8(result); } @@ -2211,7 +2284,9 @@ dcosd(PG_FUNCTION_ARGS) result = sign * cosd_q1(arg1); - check_float8_val(result, false, true); + if (unlikely(isinf(result))) + float_overflow_error(); + PG_RETURN_FLOAT8(result); } @@ -2276,7 +2351,8 @@ dcotd(PG_FUNCTION_ARGS) if (result == 0.0) result = 0.0; - check_float8_val(result, true /* cotd(0) == Inf */ , true); + /* Not checking for overflow because cotd(0) == Inf */ + PG_RETURN_FLOAT8(result); } @@ -2330,7 +2406,9 @@ dsind(PG_FUNCTION_ARGS) result = sign * sind_q1(arg1); - check_float8_val(result, false, true); + if (unlikely(isinf(result))) + float_overflow_error(); + PG_RETURN_FLOAT8(result); } @@ -2395,7 +2473,8 @@ dtand(PG_FUNCTION_ARGS) if (result == 0.0) result = 0.0; - check_float8_val(result, true /* tand(90) == Inf */ , true); + /* Not checking for overflow because tand(90) == Inf */ + PG_RETURN_FLOAT8(result); } @@ -2462,7 +2541,6 @@ dsinh(PG_FUNCTION_ARGS) result = get_float8_infinity(); } - check_float8_val(result, true, true); PG_RETURN_FLOAT8(result); } @@ -2486,7 +2564,9 @@ dcosh(PG_FUNCTION_ARGS) if (errno == ERANGE) result = get_float8_infinity(); - check_float8_val(result, true, false); + if (unlikely(result == 0.0)) + float_underflow_error(); + PG_RETURN_FLOAT8(result); } @@ -2504,7 +2584,9 @@ dtanh(PG_FUNCTION_ARGS) */ result = tanh(arg1); - check_float8_val(result, false, true); + if (unlikely(isinf(result))) + float_overflow_error(); + PG_RETURN_FLOAT8(result); } @@ -2522,7 +2604,6 @@ dasinh(PG_FUNCTION_ARGS) */ result = asinh(arg1); - check_float8_val(result, true, true); PG_RETURN_FLOAT8(result); } @@ -2548,7 +2629,6 @@ dacosh(PG_FUNCTION_ARGS) result = acosh(arg1); - check_float8_val(result, true, true); PG_RETURN_FLOAT8(result); } @@ -2583,7 +2663,6 @@ datanh(PG_FUNCTION_ARGS) else result = atanh(arg1); - check_float8_val(result, true, true); PG_RETURN_FLOAT8(result); } @@ -2784,7 +2863,8 @@ float8_combine(PG_FUNCTION_ARGS) Sx = float8_pl(Sx1, Sx2); tmp = Sx1 / N1 - Sx2 / N2; Sxx = Sxx1 + Sxx2 + N1 * N2 * tmp * tmp / N; - check_float8_val(Sxx, isinf(Sxx1) || isinf(Sxx2), true); + if (unlikely(isinf(Sxx)) && !isinf(Sxx1) && !isinf(Sxx2)) + float_overflow_error(); } /* @@ -2853,9 +2933,7 @@ float8_accum(PG_FUNCTION_ARGS) if (isinf(Sx) || isinf(Sxx)) { if (!isinf(transvalues[1]) && !isinf(newval)) - ereport(ERROR, - (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), - errmsg("value out of range: overflow"))); + float_overflow_error(); Sxx = get_float8_nan(); } @@ -2929,9 +3007,7 @@ float4_accum(PG_FUNCTION_ARGS) if (isinf(Sx) || isinf(Sxx)) { if (!isinf(transvalues[1]) && !isinf(newval)) - ereport(ERROR, - (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), - errmsg("value out of range: overflow"))); + float_overflow_error(); Sxx = get_float8_nan(); } @@ -3152,9 +3228,7 @@ float8_regr_accum(PG_FUNCTION_ARGS) (isinf(Sxy) && !isinf(transvalues[1]) && !isinf(newvalX) && !isinf(transvalues[3]) && !isinf(newvalY))) - ereport(ERROR, - (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), - errmsg("value out of range: overflow"))); + float_overflow_error(); if (isinf(Sxx)) Sxx = get_float8_nan(); @@ -3294,13 +3368,16 @@ float8_regr_combine(PG_FUNCTION_ARGS) Sx = float8_pl(Sx1, Sx2); tmp1 = Sx1 / N1 - Sx2 / N2; Sxx = Sxx1 + Sxx2 + N1 * N2 * tmp1 * tmp1 / N; - check_float8_val(Sxx, isinf(Sxx1) || isinf(Sxx2), true); + if (unlikely(isinf(Sxx)) && !isinf(Sxx1) && !isinf(Sxx2)) + float_overflow_error(); Sy = float8_pl(Sy1, Sy2); tmp2 = Sy1 / N1 - Sy2 / N2; Syy = Syy1 + Syy2 + N1 * N2 * tmp2 * tmp2 / N; - check_float8_val(Syy, isinf(Syy1) || isinf(Syy2), true); + if (unlikely(isinf(Syy)) && !isinf(Syy1) && !isinf(Syy2)) + float_overflow_error(); Sxy = Sxy1 + Sxy2 + N1 * N2 * tmp1 * tmp2 / N; - check_float8_val(Sxy, isinf(Sxy1) || isinf(Sxy2), true); + if (unlikely(isinf(Sxy)) && !isinf(Sxy1) && !isinf(Sxy2)) + float_overflow_error(); } /* |