Re: [BUGS] BUG #2846: inconsistent and confusing - Mailing list pgsql-patches
From | Bruce Momjian |
---|---|
Subject | Re: [BUGS] BUG #2846: inconsistent and confusing |
Date | |
Msg-id | 200612282033.kBSKXrt01855@momjian.us Whole thread Raw |
In response to | Re: [BUGS] BUG #2846: inconsistent and confusing handling of (Tom Lane <tgl@sss.pgh.pa.us>) |
Responses |
Re: [BUGS] BUG #2846: inconsistent and confusing
|
List | pgsql-patches |
Tom Lane wrote: > No, because you are still comparing against FLOAT4_MAX. I'm suggesting > that only an actual infinity should be rejected. Even that is contrary > to IEEE spec, though. > > The other problem with this coding technique is that it must invoke > isinf three times when the typical case really only requires one (if the > output isn't inf there is no need to perform isinf on the inputs). > If we're going to check for overflow at all, I think we should lose the > subroutine and just do > > if (isinf(result) && > !(isinf(arg1) || isinf(arg2))) > ereport(...OVERFLOW...); I wasn't excited about doing one isinf() call to avoid three, so I just made a fast isinf() macro: /* We call isinf() a lot, so we use a fast version in this file */ #define fast_isinf(val) (((val) < DBL_MIN || (val) > DBL_MAX) && isinf(val)) and used that instead of the direct isinf() call. (We do call fabs() in the Check* routines. Should we be using our own Abs()?) The new patch also uses float8 for float4 computations, and adds a comment about why (avoid underflow in some cases). In looking at the idea of checking for zero as an underflow, I found most transcendental functions already had such a check, so I moved the check into the Check*() routines, and added checks for multiplication/division underflow to zero. The only outstanding uncaught underflow is from addition/subtraction. -- Bruce Momjian bruce@momjian.us EnterpriseDB http://www.enterprisedb.com + If your life is a hard drive, Christ can be your backup. + Index: src/backend/utils/adt/float.c =================================================================== RCS file: /cvsroot/pgsql/src/backend/utils/adt/float.c,v retrieving revision 1.131 diff -c -c -r1.131 float.c *** src/backend/utils/adt/float.c 23 Dec 2006 02:13:24 -0000 1.131 --- src/backend/utils/adt/float.c 28 Dec 2006 20:32:32 -0000 *************** *** 87,92 **** --- 87,95 ---- #define NAN (*(const double *) nan) #endif + /* We call isinf() a lot, so we use a fast version in this file */ + #define fast_isinf(val) (((val) < DBL_MIN || (val) > DBL_MAX) && isinf(val)) + /* not sure what the following should be, but better to make it over-sufficient */ #define MAXFLOATWIDTH 64 #define MAXDOUBLEWIDTH 128 *************** *** 104,111 **** int extra_float_digits = 0; /* Added to DBL_DIG or FLT_DIG */ ! static void CheckFloat4Val(double val); ! static void CheckFloat8Val(double val); static int float4_cmp_internal(float4 a, float4 b); static int float8_cmp_internal(float8 a, float8 b); --- 107,114 ---- int extra_float_digits = 0; /* Added to DBL_DIG or FLT_DIG */ ! static void CheckFloat4Val(double val, bool has_inf_args, bool zero_is_valid); ! static void CheckFloat8Val(double val, bool has_inf_args, bool zero_is_valid); static int float4_cmp_internal(float4 a, float4 b); static int float8_cmp_internal(float8 a, float8 b); *************** *** 211,219 **** * raise an ereport() error if it is */ static void ! CheckFloat4Val(double val) { ! if (fabs(val) > FLOAT4_MAX) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("type \"real\" value out of range: overflow"))); --- 214,223 ---- * raise an ereport() error if it is */ static void ! CheckFloat4Val(double val, bool has_inf_args, bool zero_is_valid) { ! /* If one of the input arguments was infinity, allow an infinite result */ ! if (fabs(val) > FLOAT4_MAX && (!fast_isinf(val) || !has_inf_args)) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("type \"real\" value out of range: overflow"))); *************** *** 230,242 **** * raise an ereport() error if it is */ static void ! CheckFloat8Val(double val) { ! if (fabs(val) > FLOAT8_MAX) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("type \"double precision\" value out of range: overflow"))); ! if (val != 0.0 && fabs(val) < FLOAT8_MIN) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("type \"double precision\" value out of range: underflow"))); --- 234,263 ---- * raise an ereport() error if it is */ static void ! CheckFloat8Val(double val, bool has_inf_args, bool zero_is_valid) { ! /* ! * Computations that slightly exceed FLOAT8_MAX are non-Infinity, ! * but those that greatly exceed FLOAT8_MAX become Infinity. Therefore ! * it is difficult to tell if a value is really infinity or the result ! * of an overflow. The solution is to use a boolean indicating if ! * the input arguments were infiity, meaning an infinite result is ! * probably not the result of an overflow. This allows various ! * computations like SELECT 'Inf'::float8 + 5. ! */ ! if (fabs(val) > FLOAT8_MAX && (!fast_isinf(val) || !has_inf_args)) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("type \"double precision\" value out of range: overflow"))); ! /* ! * Underflow has similar issues to overflow, i.e. if a computation is ! * slighly smaller than FLOAT8_MIN, the result is non-zero, but if it is ! * much smaller than FLOAT8_MIN, the value becomes zero. However, ! * unlike overflow, zero is not a special value and can be the result ! * of a computation, so we pass in a boolean indicating if zero is ! * a valid result. ! */ ! if ((val != 0.0 && fabs(val) < FLOAT8_MIN) || (val == 0 && !zero_is_valid)) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("type \"double precision\" value out of range: underflow"))); *************** *** 334,340 **** * input is "infinity" we have to skip over "inity". Also, it may * return positive infinity for "-inf". */ ! if (isinf(val)) { if (pg_strncasecmp(num, "Infinity", 8) == 0) { --- 355,361 ---- * input is "infinity" we have to skip over "inity". Also, it may * return positive infinity for "-inf". */ ! if (fast_isinf(val)) { if (pg_strncasecmp(num, "Infinity", 8) == 0) { *************** *** 369,376 **** * if we get here, we have a legal double, still need to check to see if * it's a legal float4 */ ! if (!isinf(val)) ! CheckFloat4Val(val); PG_RETURN_FLOAT4((float4) val); } --- 390,396 ---- * if we get here, we have a legal double, still need to check to see if * it's a legal float4 */ ! CheckFloat4Val(val, true, true); PG_RETURN_FLOAT4((float4) val); } *************** *** 527,533 **** * input is "infinity" we have to skip over "inity". Also, it may * return positive infinity for "-inf". */ ! if (isinf(val)) { if (pg_strncasecmp(num, "Infinity", 8) == 0) { --- 547,553 ---- * input is "infinity" we have to skip over "inity". Also, it may * return positive infinity for "-inf". */ ! if (fast_isinf(val)) { if (pg_strncasecmp(num, "Infinity", 8) == 0) { *************** *** 558,565 **** errmsg("invalid input syntax for type double precision: \"%s\"", orig_num))); ! if (!isinf(val)) ! CheckFloat8Val(val); PG_RETURN_FLOAT8(val); } --- 578,584 ---- errmsg("invalid input syntax for type double precision: \"%s\"", orig_num))); ! CheckFloat8Val(val, true, true); PG_RETURN_FLOAT8(val); } *************** *** 652,659 **** float4um(PG_FUNCTION_ARGS) { float4 arg1 = PG_GETARG_FLOAT4(0); ! PG_RETURN_FLOAT4((float4) -arg1); } Datum --- 671,682 ---- float4um(PG_FUNCTION_ARGS) { float4 arg1 = PG_GETARG_FLOAT4(0); + float4 result; + + result = ((arg1 != 0) ? -(arg1) : arg1); ! CheckFloat4Val(result, fast_isinf(arg1), true); ! PG_RETURN_FLOAT4(result); } Datum *************** *** 705,716 **** float8abs(PG_FUNCTION_ARGS) { float8 arg1 = PG_GETARG_FLOAT8(0); - float8 result; ! result = fabs(arg1); ! ! CheckFloat8Val(result); ! PG_RETURN_FLOAT8(result); } --- 728,735 ---- float8abs(PG_FUNCTION_ARGS) { float8 arg1 = PG_GETARG_FLOAT8(0); ! PG_RETURN_FLOAT8(fabs(arg1)); } *************** *** 725,731 **** result = ((arg1 != 0) ? -(arg1) : arg1); ! CheckFloat8Val(result); PG_RETURN_FLOAT8(result); } --- 744,750 ---- result = ((arg1 != 0) ? -(arg1) : arg1); ! CheckFloat8Val(result, fast_isinf(arg1), true); PG_RETURN_FLOAT8(result); } *************** *** 781,824 **** Datum float4pl(PG_FUNCTION_ARGS) { ! float4 arg1 = PG_GETARG_FLOAT4(0); ! float4 arg2 = PG_GETARG_FLOAT4(1); double result; result = arg1 + arg2; ! CheckFloat4Val(result); PG_RETURN_FLOAT4((float4) result); } Datum float4mi(PG_FUNCTION_ARGS) { ! float4 arg1 = PG_GETARG_FLOAT4(0); ! float4 arg2 = PG_GETARG_FLOAT4(1); double result; result = arg1 - arg2; ! CheckFloat4Val(result); PG_RETURN_FLOAT4((float4) result); } Datum float4mul(PG_FUNCTION_ARGS) { ! float4 arg1 = PG_GETARG_FLOAT4(0); ! float4 arg2 = PG_GETARG_FLOAT4(1); double result; result = arg1 * arg2; ! CheckFloat4Val(result); PG_RETURN_FLOAT4((float4) result); } Datum float4div(PG_FUNCTION_ARGS) { ! float4 arg1 = PG_GETARG_FLOAT4(0); ! float4 arg2 = PG_GETARG_FLOAT4(1); double result; if (arg2 == 0.0) --- 800,849 ---- Datum float4pl(PG_FUNCTION_ARGS) { ! /* ! * Use float8 so that we have a larger underflow range. ! * Some compilers do not promote float to double in ! * computations. ! */ ! float8 arg1 = PG_GETARG_FLOAT4(0); ! float8 arg2 = PG_GETARG_FLOAT4(1); double result; result = arg1 + arg2; ! CheckFloat4Val(result, fast_isinf(arg1) || fast_isinf(arg2), true); PG_RETURN_FLOAT4((float4) result); } Datum float4mi(PG_FUNCTION_ARGS) { ! float8 arg1 = PG_GETARG_FLOAT4(0); ! float8 arg2 = PG_GETARG_FLOAT4(1); double result; result = arg1 - arg2; ! CheckFloat4Val(result, fast_isinf(arg1) || fast_isinf(arg2), true); PG_RETURN_FLOAT4((float4) result); } Datum float4mul(PG_FUNCTION_ARGS) { ! float8 arg1 = PG_GETARG_FLOAT4(0); ! float8 arg2 = PG_GETARG_FLOAT4(1); double result; result = arg1 * arg2; ! CheckFloat4Val(result, fast_isinf(arg1) || fast_isinf(arg2), ! arg1 == 0 || arg2 == 0); PG_RETURN_FLOAT4((float4) result); } Datum float4div(PG_FUNCTION_ARGS) { ! float8 arg1 = PG_GETARG_FLOAT4(0); ! float8 arg2 = PG_GETARG_FLOAT4(1); double result; if (arg2 == 0.0) *************** *** 827,835 **** errmsg("division by zero"))); /* Do division in float8, then check for overflow */ ! result = (float8) arg1 / (float8) arg2; ! CheckFloat4Val(result); PG_RETURN_FLOAT4((float4) result); } --- 852,860 ---- errmsg("division by zero"))); /* Do division in float8, then check for overflow */ ! result = arg1 / arg2; ! CheckFloat4Val(result, fast_isinf(arg1) || fast_isinf(arg2), arg1 == 0); PG_RETURN_FLOAT4((float4) result); } *************** *** 848,854 **** result = arg1 + arg2; ! CheckFloat8Val(result); PG_RETURN_FLOAT8(result); } --- 873,879 ---- result = arg1 + arg2; ! CheckFloat8Val(result, fast_isinf(arg1) || fast_isinf(arg2), true); PG_RETURN_FLOAT8(result); } *************** *** 861,867 **** result = arg1 - arg2; ! CheckFloat8Val(result); PG_RETURN_FLOAT8(result); } --- 886,892 ---- result = arg1 - arg2; ! CheckFloat8Val(result, fast_isinf(arg1) || fast_isinf(arg2), true); PG_RETURN_FLOAT8(result); } *************** *** 874,880 **** result = arg1 * arg2; ! CheckFloat8Val(result); PG_RETURN_FLOAT8(result); } --- 899,906 ---- result = arg1 * arg2; ! CheckFloat8Val(result, fast_isinf(arg1) || fast_isinf(arg2), ! arg1 == 0 || arg2 == 0); PG_RETURN_FLOAT8(result); } *************** *** 892,898 **** result = arg1 / arg2; ! CheckFloat8Val(result); PG_RETURN_FLOAT8(result); } --- 918,924 ---- result = arg1 / arg2; ! CheckFloat8Val(result, fast_isinf(arg1) || fast_isinf(arg2), arg1 == 0); PG_RETURN_FLOAT8(result); } *************** *** 1142,1148 **** { float8 num = PG_GETARG_FLOAT8(0); ! CheckFloat4Val(num); PG_RETURN_FLOAT4((float4) num); } --- 1168,1174 ---- { float8 num = PG_GETARG_FLOAT8(0); ! CheckFloat4Val(num, fast_isinf(num), true); PG_RETURN_FLOAT4((float4) num); } *************** *** 1157,1163 **** float8 num = PG_GETARG_FLOAT8(0); int32 result; ! if (num < INT_MIN || num > INT_MAX) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("integer out of range"))); --- 1183,1190 ---- float8 num = PG_GETARG_FLOAT8(0); int32 result; ! /* 'Inf' is handled by INT_MAX */ ! if (num < INT_MIN || num > INT_MAX || isnan(num)) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("integer out of range"))); *************** *** 1176,1182 **** float8 num = PG_GETARG_FLOAT8(0); int16 result; ! if (num < SHRT_MIN || num > SHRT_MAX) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("smallint out of range"))); --- 1203,1209 ---- float8 num = PG_GETARG_FLOAT8(0); int16 result; ! if (num < SHRT_MIN || num > SHRT_MAX || isnan(num)) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("smallint out of range"))); *************** *** 1223,1229 **** float4 num = PG_GETARG_FLOAT4(0); int32 result; ! if (num < INT_MIN || num > INT_MAX) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("integer out of range"))); --- 1250,1256 ---- float4 num = PG_GETARG_FLOAT4(0); int32 result; ! if (num < INT_MIN || num > INT_MAX || isnan(num)) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("integer out of range"))); *************** *** 1242,1248 **** float4 num = PG_GETARG_FLOAT4(0); int16 result; ! if (num < SHRT_MIN || num > SHRT_MAX) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("smallint out of range"))); --- 1269,1275 ---- float4 num = PG_GETARG_FLOAT4(0); int16 result; ! if (num < SHRT_MIN || num > SHRT_MAX || isnan(num)) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("smallint out of range"))); *************** *** 1485,1491 **** result = sqrt(arg1); ! CheckFloat8Val(result); PG_RETURN_FLOAT8(result); } --- 1512,1518 ---- result = sqrt(arg1); ! CheckFloat8Val(result, fast_isinf(arg1), arg1 == 0); PG_RETURN_FLOAT8(result); } *************** *** 1500,1505 **** --- 1527,1533 ---- float8 result; result = cbrt(arg1); + CheckFloat8Val(result, fast_isinf(arg1), arg1 == 0); PG_RETURN_FLOAT8(result); } *************** *** 1539,1545 **** (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("result is out of range"))); ! CheckFloat8Val(result); PG_RETURN_FLOAT8(result); } --- 1567,1573 ---- (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("result is out of range"))); ! CheckFloat8Val(result, fast_isinf(arg1) || fast_isinf(arg2), arg1 == 0); PG_RETURN_FLOAT8(result); } *************** *** 1555,1575 **** /* * We must check both for errno getting set and for a NaN result, in order ! * to deal with the vagaries of different platforms. Also, a zero result ! * implies unreported underflow. */ errno = 0; result = exp(arg1); ! if (errno != 0 || result == 0.0 ! #ifdef HAVE_FINITE ! || !finite(result) ! #endif ! ) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("result is out of range"))); ! CheckFloat8Val(result); PG_RETURN_FLOAT8(result); } --- 1583,1598 ---- /* * We must check both for errno getting set and for a NaN result, in order ! * to deal with the vagaries of different platforms. */ errno = 0; result = exp(arg1); ! if (errno != 0) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("result is out of range"))); ! CheckFloat8Val(result, fast_isinf(arg1), false); PG_RETURN_FLOAT8(result); } *************** *** 1598,1604 **** result = log(arg1); ! CheckFloat8Val(result); PG_RETURN_FLOAT8(result); } --- 1621,1627 ---- result = log(arg1); ! CheckFloat8Val(result, fast_isinf(arg1), arg1 == 1); PG_RETURN_FLOAT8(result); } *************** *** 1628,1634 **** result = log10(arg1); ! CheckFloat8Val(result); PG_RETURN_FLOAT8(result); } --- 1651,1657 ---- result = log10(arg1); ! CheckFloat8Val(result, fast_isinf(arg1), arg1 == 1); PG_RETURN_FLOAT8(result); } *************** *** 1644,1659 **** errno = 0; result = acos(arg1); ! if (errno != 0 ! #ifdef HAVE_FINITE ! || !finite(result) ! #endif ! ) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("input is out of range"))); ! CheckFloat8Val(result); PG_RETURN_FLOAT8(result); } --- 1667,1678 ---- errno = 0; result = acos(arg1); ! if (errno != 0) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("input is out of range"))); ! CheckFloat8Val(result, fast_isinf(arg1), true); PG_RETURN_FLOAT8(result); } *************** *** 1669,1684 **** errno = 0; result = asin(arg1); ! if (errno != 0 ! #ifdef HAVE_FINITE ! || !finite(result) ! #endif ! ) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("input is out of range"))); ! CheckFloat8Val(result); PG_RETURN_FLOAT8(result); } --- 1688,1699 ---- errno = 0; result = asin(arg1); ! if (errno != 0) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("input is out of range"))); ! CheckFloat8Val(result, fast_isinf(arg1), true); PG_RETURN_FLOAT8(result); } *************** *** 1694,1709 **** errno = 0; result = atan(arg1); ! if (errno != 0 ! #ifdef HAVE_FINITE ! || !finite(result) ! #endif ! ) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("input is out of range"))); ! CheckFloat8Val(result); PG_RETURN_FLOAT8(result); } --- 1709,1720 ---- errno = 0; result = atan(arg1); ! if (errno != 0) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("input is out of range"))); ! CheckFloat8Val(result, fast_isinf(arg1), arg1 == 0); PG_RETURN_FLOAT8(result); } *************** *** 1720,1735 **** errno = 0; result = atan2(arg1, arg2); ! if (errno != 0 ! #ifdef HAVE_FINITE ! || !finite(result) ! #endif ! ) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("input is out of range"))); ! CheckFloat8Val(result); PG_RETURN_FLOAT8(result); } --- 1731,1742 ---- errno = 0; result = atan2(arg1, arg2); ! if (errno != 0) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("input is out of range"))); ! CheckFloat8Val(result, fast_isinf(arg1) || fast_isinf(arg2), arg2 == 0); PG_RETURN_FLOAT8(result); } *************** *** 1745,1760 **** errno = 0; result = cos(arg1); ! if (errno != 0 ! #ifdef HAVE_FINITE ! || !finite(result) ! #endif ! ) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("input is out of range"))); ! CheckFloat8Val(result); PG_RETURN_FLOAT8(result); } --- 1752,1763 ---- errno = 0; result = cos(arg1); ! if (errno != 0) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("input is out of range"))); ! CheckFloat8Val(result, fast_isinf(arg1), true); PG_RETURN_FLOAT8(result); } *************** *** 1770,1786 **** errno = 0; result = tan(arg1); ! if (errno != 0 || result == 0.0 ! #ifdef HAVE_FINITE ! || !finite(result) ! #endif ! ) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("input is out of range"))); result = 1.0 / result; ! CheckFloat8Val(result); PG_RETURN_FLOAT8(result); } --- 1773,1785 ---- errno = 0; result = tan(arg1); ! if (errno != 0) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("input is out of range"))); result = 1.0 / result; ! CheckFloat8Val(result, fast_isinf(arg1), true); PG_RETURN_FLOAT8(result); } *************** *** 1796,1811 **** errno = 0; result = sin(arg1); ! if (errno != 0 ! #ifdef HAVE_FINITE ! || !finite(result) ! #endif ! ) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("input is out of range"))); ! CheckFloat8Val(result); PG_RETURN_FLOAT8(result); } --- 1795,1806 ---- errno = 0; result = sin(arg1); ! if (errno != 0) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("input is out of range"))); ! CheckFloat8Val(result, fast_isinf(arg1), true); PG_RETURN_FLOAT8(result); } *************** *** 1830,1836 **** (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("input is out of range"))); ! CheckFloat8Val(result); PG_RETURN_FLOAT8(result); } --- 1825,1831 ---- (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("input is out of range"))); ! CheckFloat8Val(result, fast_isinf(arg1), arg1 == 0); PG_RETURN_FLOAT8(result); } *************** *** 1846,1852 **** result = arg1 * (180.0 / M_PI); ! CheckFloat8Val(result); PG_RETURN_FLOAT8(result); } --- 1841,1847 ---- result = arg1 * (180.0 / M_PI); ! CheckFloat8Val(result, fast_isinf(arg1), arg1 == 0); PG_RETURN_FLOAT8(result); } *************** *** 1872,1878 **** result = arg1 * (M_PI / 180.0); ! CheckFloat8Val(result); PG_RETURN_FLOAT8(result); } --- 1867,1873 ---- result = arg1 * (M_PI / 180.0); ! CheckFloat8Val(result, fast_isinf(arg1), arg1 == 0); PG_RETURN_FLOAT8(result); } *************** *** 1963,1970 **** N += 1.0; sumX += newval; sumX2 += newval * newval; ! /* * If we're invoked by nodeAgg, we can cheat and modify our first * parameter in-place to reduce palloc overhead. Otherwise we construct a --- 1958,1967 ---- N += 1.0; sumX += newval; + CheckFloat8Val(sumX, fast_isinf(transvalues[1]) || fast_isinf(newval), true); sumX2 += newval * newval; ! CheckFloat8Val(sumX2, fast_isinf(transvalues[2]) || fast_isinf(newval), true); ! /* * If we're invoked by nodeAgg, we can cheat and modify our first * parameter in-place to reduce palloc overhead. Otherwise we construct a *************** *** 1999,2023 **** float4_accum(PG_FUNCTION_ARGS) { ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0); ! float4 newval4 = PG_GETARG_FLOAT4(1); float8 *transvalues; float8 N, sumX, ! sumX2, ! newval; transvalues = check_float8_array(transarray, "float4_accum", 3); N = transvalues[0]; sumX = transvalues[1]; sumX2 = transvalues[2]; - /* Do arithmetic in float8 for best accuracy */ - newval = newval4; - N += 1.0; sumX += newval; sumX2 += newval * newval; ! /* * If we're invoked by nodeAgg, we can cheat and modify our first * parameter in-place to reduce palloc overhead. Otherwise we construct a --- 1996,2023 ---- float4_accum(PG_FUNCTION_ARGS) { ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0); ! /* ! * Use float8 so that we have a larger underflow range. ! * Some compilers do not promote float to double in ! * computations. ! */ ! float8 newval = PG_GETARG_FLOAT4(1); float8 *transvalues; float8 N, sumX, ! sumX2; transvalues = check_float8_array(transarray, "float4_accum", 3); N = transvalues[0]; sumX = transvalues[1]; sumX2 = transvalues[2]; N += 1.0; sumX += newval; + CheckFloat4Val(sumX, fast_isinf(transvalues[1]) || fast_isinf(newval), true); sumX2 += newval * newval; ! CheckFloat4Val(sumX2, fast_isinf(transvalues[2]) || fast_isinf(newval), true); ! /* * If we're invoked by nodeAgg, we can cheat and modify our first * parameter in-place to reduce palloc overhead. Otherwise we construct a *************** *** 2088,2093 **** --- 2088,2094 ---- PG_RETURN_NULL(); numerator = N * sumX2 - sumX * sumX; + CheckFloat8Val(numerator, fast_isinf(sumX2) || fast_isinf(sumX), true); /* Watch out for roundoff error producing a negative numerator */ if (numerator <= 0.0) *************** *** 2116,2121 **** --- 2117,2123 ---- PG_RETURN_NULL(); numerator = N * sumX2 - sumX * sumX; + CheckFloat8Val(numerator, fast_isinf(sumX2) || fast_isinf(sumX), true); /* Watch out for roundoff error producing a negative numerator */ if (numerator <= 0.0) *************** *** 2144,2149 **** --- 2146,2152 ---- PG_RETURN_NULL(); numerator = N * sumX2 - sumX * sumX; + CheckFloat8Val(numerator, fast_isinf(sumX2) || fast_isinf(sumX), true); /* Watch out for roundoff error producing a negative numerator */ if (numerator <= 0.0) *************** *** 2172,2177 **** --- 2175,2181 ---- PG_RETURN_NULL(); numerator = N * sumX2 - sumX * sumX; + CheckFloat8Val(numerator, fast_isinf(sumX2) || fast_isinf(sumX), true); /* Watch out for roundoff error producing a negative numerator */ if (numerator <= 0.0) *************** *** 2220,2230 **** N += 1.0; sumX += newvalX; sumX2 += newvalX * newvalX; sumY += newvalY; sumY2 += newvalY * newvalY; sumXY += newvalX * newvalY; ! /* * If we're invoked by nodeAgg, we can cheat and modify our first * parameter in-place to reduce palloc overhead. Otherwise we construct a --- 2224,2240 ---- N += 1.0; sumX += newvalX; + CheckFloat8Val(sumX, fast_isinf(transvalues[1]) || fast_isinf(newvalX), true); sumX2 += newvalX * newvalX; + CheckFloat8Val(sumX2, fast_isinf(transvalues[2]) || fast_isinf(newvalX), true); sumY += newvalY; + CheckFloat8Val(sumY, fast_isinf(transvalues[3]) || fast_isinf(newvalY), true); sumY2 += newvalY * newvalY; + CheckFloat8Val(sumY2, fast_isinf(transvalues[4]) || fast_isinf(newvalY), true); sumXY += newvalX * newvalY; ! CheckFloat8Val(sumXY, fast_isinf(transvalues[5]) || fast_isinf(newvalX) || ! fast_isinf(newvalY), true); ! /* * If we're invoked by nodeAgg, we can cheat and modify our first * parameter in-place to reduce palloc overhead. Otherwise we construct a *************** *** 2282,2287 **** --- 2292,2298 ---- PG_RETURN_NULL(); numerator = N * sumX2 - sumX * sumX; + CheckFloat8Val(numerator, fast_isinf(sumX2) || fast_isinf(sumX), true); /* Watch out for roundoff error producing a negative numerator */ if (numerator <= 0.0) *************** *** 2310,2315 **** --- 2321,2327 ---- PG_RETURN_NULL(); numerator = N * sumY2 - sumY * sumY; + CheckFloat8Val(numerator, fast_isinf(sumY2) || fast_isinf(sumY), true); /* Watch out for roundoff error producing a negative numerator */ if (numerator <= 0.0) *************** *** 2340,2345 **** --- 2352,2359 ---- PG_RETURN_NULL(); numerator = N * sumXY - sumX * sumY; + CheckFloat8Val(numerator, fast_isinf(sumXY) || fast_isinf(sumX) || + fast_isinf(sumY), true); /* A negative result is valid here */ *************** *** 2406,2411 **** --- 2420,2427 ---- PG_RETURN_NULL(); numerator = N * sumXY - sumX * sumY; + CheckFloat8Val(numerator, fast_isinf(sumXY) || fast_isinf(sumX) || + fast_isinf(sumY), true); PG_RETURN_FLOAT8(numerator / (N * N)); } *************** *** 2432,2437 **** --- 2448,2455 ---- PG_RETURN_NULL(); numerator = N * sumXY - sumX * sumY; + CheckFloat8Val(numerator, fast_isinf(sumXY) || fast_isinf(sumX) || + fast_isinf(sumY), true); PG_RETURN_FLOAT8(numerator / (N * (N - 1.0))); } *************** *** 2464,2471 **** --- 2482,2493 ---- PG_RETURN_NULL(); numeratorX = N * sumX2 - sumX * sumX; + CheckFloat8Val(numeratorX, fast_isinf(sumX2) || fast_isinf(sumX), true); numeratorY = N * sumY2 - sumY * sumY; + CheckFloat8Val(numeratorY, fast_isinf(sumY2) || fast_isinf(sumY), true); numeratorXY = N * sumXY - sumX * sumY; + CheckFloat8Val(numeratorXY, fast_isinf(sumXY) || fast_isinf(sumX) || + fast_isinf(sumY), true); if (numeratorX <= 0 || numeratorY <= 0) PG_RETURN_NULL(); *************** *** 2501,2508 **** --- 2523,2534 ---- PG_RETURN_NULL(); numeratorX = N * sumX2 - sumX * sumX; + CheckFloat8Val(numeratorX, fast_isinf(sumX2) || fast_isinf(sumX), true); numeratorY = N * sumY2 - sumY * sumY; + CheckFloat8Val(numeratorY, fast_isinf(sumY2) || fast_isinf(sumY), true); numeratorXY = N * sumXY - sumX * sumY; + CheckFloat8Val(numeratorXY, fast_isinf(sumXY) || fast_isinf(sumX) || + fast_isinf(sumY), true); if (numeratorX <= 0) PG_RETURN_NULL(); /* per spec, horizontal line produces 1.0 */ *************** *** 2538,2544 **** --- 2564,2573 ---- PG_RETURN_NULL(); numeratorX = N * sumX2 - sumX * sumX; + CheckFloat8Val(numeratorX, fast_isinf(sumX2) || fast_isinf(sumX), true); numeratorXY = N * sumXY - sumX * sumY; + CheckFloat8Val(numeratorXY, fast_isinf(sumXY) || fast_isinf(sumX) || + fast_isinf(sumY), true); if (numeratorX <= 0) PG_RETURN_NULL(); *************** *** 2570,2576 **** --- 2599,2608 ---- PG_RETURN_NULL(); numeratorX = N * sumX2 - sumX * sumX; + CheckFloat8Val(numeratorX, fast_isinf(sumX2) || fast_isinf(sumX), true); numeratorXXY = sumY * sumX2 - sumX * sumXY; + CheckFloat8Val(numeratorXXY, fast_isinf(sumY) || fast_isinf(sumX2) || + fast_isinf(sumX) || fast_isinf(sumXY), true); if (numeratorX <= 0) PG_RETURN_NULL(); *************** *** 2593,2635 **** Datum float48pl(PG_FUNCTION_ARGS) { ! float4 arg1 = PG_GETARG_FLOAT4(0); float8 arg2 = PG_GETARG_FLOAT8(1); float8 result; result = arg1 + arg2; ! CheckFloat8Val(result); PG_RETURN_FLOAT8(result); } Datum float48mi(PG_FUNCTION_ARGS) { ! float4 arg1 = PG_GETARG_FLOAT4(0); float8 arg2 = PG_GETARG_FLOAT8(1); float8 result; result = arg1 - arg2; ! CheckFloat8Val(result); PG_RETURN_FLOAT8(result); } Datum float48mul(PG_FUNCTION_ARGS) { ! float4 arg1 = PG_GETARG_FLOAT4(0); float8 arg2 = PG_GETARG_FLOAT8(1); float8 result; result = arg1 * arg2; ! CheckFloat8Val(result); PG_RETURN_FLOAT8(result); } Datum float48div(PG_FUNCTION_ARGS) { ! float4 arg1 = PG_GETARG_FLOAT4(0); float8 arg2 = PG_GETARG_FLOAT8(1); float8 result; --- 2625,2673 ---- Datum float48pl(PG_FUNCTION_ARGS) { ! /* ! * Use float8 so that we have a larger underflow range. ! * Some compilers do not promote float to double in ! * computations. ! */ ! float8 arg1 = PG_GETARG_FLOAT4(0); float8 arg2 = PG_GETARG_FLOAT8(1); float8 result; result = arg1 + arg2; ! CheckFloat8Val(result, fast_isinf(arg1) || fast_isinf(arg2), true); PG_RETURN_FLOAT8(result); } Datum float48mi(PG_FUNCTION_ARGS) { ! float8 arg1 = PG_GETARG_FLOAT4(0); float8 arg2 = PG_GETARG_FLOAT8(1); float8 result; result = arg1 - arg2; ! CheckFloat8Val(result, fast_isinf(arg1) || fast_isinf(arg2), true); PG_RETURN_FLOAT8(result); } Datum float48mul(PG_FUNCTION_ARGS) { ! float8 arg1 = PG_GETARG_FLOAT4(0); float8 arg2 = PG_GETARG_FLOAT8(1); float8 result; result = arg1 * arg2; ! CheckFloat8Val(result, fast_isinf(arg1) || fast_isinf(arg2), ! arg1 == 0 || arg2 == 0); PG_RETURN_FLOAT8(result); } Datum float48div(PG_FUNCTION_ARGS) { ! float8 arg1 = PG_GETARG_FLOAT4(0); float8 arg2 = PG_GETARG_FLOAT8(1); float8 result; *************** *** 2639,2645 **** errmsg("division by zero"))); result = arg1 / arg2; ! CheckFloat8Val(result); PG_RETURN_FLOAT8(result); } --- 2677,2683 ---- errmsg("division by zero"))); result = arg1 / arg2; ! CheckFloat8Val(result, fast_isinf(arg1) || fast_isinf(arg2), arg1 == 0); PG_RETURN_FLOAT8(result); } *************** *** 2653,2664 **** float84pl(PG_FUNCTION_ARGS) { float8 arg1 = PG_GETARG_FLOAT8(0); ! float4 arg2 = PG_GETARG_FLOAT4(1); float8 result; result = arg1 + arg2; ! CheckFloat8Val(result); PG_RETURN_FLOAT8(result); } --- 2691,2702 ---- float84pl(PG_FUNCTION_ARGS) { float8 arg1 = PG_GETARG_FLOAT8(0); ! float8 arg2 = PG_GETARG_FLOAT4(1); float8 result; result = arg1 + arg2; ! CheckFloat8Val(result, fast_isinf(arg1) || fast_isinf(arg2), true); PG_RETURN_FLOAT8(result); } *************** *** 2666,2677 **** float84mi(PG_FUNCTION_ARGS) { float8 arg1 = PG_GETARG_FLOAT8(0); ! float4 arg2 = PG_GETARG_FLOAT4(1); float8 result; result = arg1 - arg2; ! CheckFloat8Val(result); PG_RETURN_FLOAT8(result); } --- 2704,2715 ---- float84mi(PG_FUNCTION_ARGS) { float8 arg1 = PG_GETARG_FLOAT8(0); ! float8 arg2 = PG_GETARG_FLOAT4(1); float8 result; result = arg1 - arg2; ! CheckFloat8Val(result, fast_isinf(arg1) || fast_isinf(arg2), true); PG_RETURN_FLOAT8(result); } *************** *** 2679,2690 **** float84mul(PG_FUNCTION_ARGS) { float8 arg1 = PG_GETARG_FLOAT8(0); ! float4 arg2 = PG_GETARG_FLOAT4(1); float8 result; result = arg1 * arg2; ! CheckFloat8Val(result); PG_RETURN_FLOAT8(result); } --- 2717,2729 ---- float84mul(PG_FUNCTION_ARGS) { float8 arg1 = PG_GETARG_FLOAT8(0); ! float8 arg2 = PG_GETARG_FLOAT4(1); float8 result; result = arg1 * arg2; ! CheckFloat8Val(result, fast_isinf(arg1) || fast_isinf(arg2), ! arg1 == 0 || arg2 == 0); PG_RETURN_FLOAT8(result); } *************** *** 2692,2698 **** float84div(PG_FUNCTION_ARGS) { float8 arg1 = PG_GETARG_FLOAT8(0); ! float4 arg2 = PG_GETARG_FLOAT4(1); float8 result; if (arg2 == 0.0) --- 2731,2737 ---- float84div(PG_FUNCTION_ARGS) { float8 arg1 = PG_GETARG_FLOAT8(0); ! float8 arg2 = PG_GETARG_FLOAT4(1); float8 result; if (arg2 == 0.0) *************** *** 2702,2708 **** result = arg1 / arg2; ! CheckFloat8Val(result); PG_RETURN_FLOAT8(result); } --- 2741,2747 ---- result = arg1 / arg2; ! CheckFloat8Val(result, fast_isinf(arg1) || fast_isinf(arg2), arg1 == 0); PG_RETURN_FLOAT8(result); } Index: src/backend/utils/adt/int.c =================================================================== RCS file: /cvsroot/pgsql/src/backend/utils/adt/int.c,v retrieving revision 1.75 diff -c -c -r1.75 int.c *** src/backend/utils/adt/int.c 4 Oct 2006 00:29:59 -0000 1.75 --- src/backend/utils/adt/int.c 28 Dec 2006 20:32:33 -0000 *************** *** 1124,1129 **** --- 1124,1134 ---- ereport(ERROR, (errcode(ERRCODE_DIVISION_BY_ZERO), errmsg("division by zero"))); + + /* SELECT ((-2147483648)::int4) % (-1); causes a floating point exception */ + if (arg1 == INT_MIN && arg2 == -1) + PG_RETURN_INT32(0); + /* No overflow is possible */ PG_RETURN_INT32(arg1 % arg2); Index: src/test/regress/expected/float4.out =================================================================== RCS file: /cvsroot/pgsql/src/test/regress/expected/float4.out,v retrieving revision 1.13 diff -c -c -r1.13 float4.out *** src/test/regress/expected/float4.out 7 Apr 2005 01:51:40 -0000 1.13 --- src/test/regress/expected/float4.out 28 Dec 2006 20:32:35 -0000 *************** *** 72,78 **** SELECT ' INFINITY x'::float4; ERROR: invalid input syntax for type real: " INFINITY x" SELECT 'Infinity'::float4 + 100.0; ! ERROR: type "double precision" value out of range: overflow SELECT 'Infinity'::float4 / 'Infinity'::float4; ?column? ---------- --- 72,82 ---- SELECT ' INFINITY x'::float4; ERROR: invalid input syntax for type real: " INFINITY x" SELECT 'Infinity'::float4 + 100.0; ! ?column? ! ---------- ! Infinity ! (1 row) ! SELECT 'Infinity'::float4 / 'Infinity'::float4; ?column? ---------- Index: src/test/regress/expected/float8.out =================================================================== RCS file: /cvsroot/pgsql/src/test/regress/expected/float8.out,v retrieving revision 1.24 diff -c -c -r1.24 float8.out *** src/test/regress/expected/float8.out 8 Jun 2005 21:15:29 -0000 1.24 --- src/test/regress/expected/float8.out 28 Dec 2006 20:32:35 -0000 *************** *** 72,78 **** SELECT ' INFINITY x'::float8; ERROR: invalid input syntax for type double precision: " INFINITY x" SELECT 'Infinity'::float8 + 100.0; ! ERROR: type "double precision" value out of range: overflow SELECT 'Infinity'::float8 / 'Infinity'::float8; ?column? ---------- --- 72,82 ---- SELECT ' INFINITY x'::float8; ERROR: invalid input syntax for type double precision: " INFINITY x" SELECT 'Infinity'::float8 + 100.0; ! ?column? ! ---------- ! Infinity ! (1 row) ! SELECT 'Infinity'::float8 / 'Infinity'::float8; ?column? ---------- *************** *** 350,356 **** SELECT '' AS bad, ln(f.f1) from FLOAT8_TBL f where f.f1 < '0.0' ; ERROR: cannot take logarithm of a negative number SELECT '' AS bad, exp(f.f1) from FLOAT8_TBL f; ! ERROR: result is out of range SELECT '' AS bad, f.f1 / '0.0' from FLOAT8_TBL f; ERROR: division by zero SELECT '' AS five, * FROM FLOAT8_TBL; --- 354,360 ---- SELECT '' AS bad, ln(f.f1) from FLOAT8_TBL f where f.f1 < '0.0' ; ERROR: cannot take logarithm of a negative number SELECT '' AS bad, exp(f.f1) from FLOAT8_TBL f; ! ERROR: type "double precision" value out of range: underflow SELECT '' AS bad, f.f1 / '0.0' from FLOAT8_TBL f; ERROR: division by zero SELECT '' AS five, * FROM FLOAT8_TBL;
pgsql-patches by date: