diff --git a/src/backend/utils/adt/float.c b/src/backend/utils/adt/float.c new file mode 100644 index 8f34209..4ce0129 *** a/src/backend/utils/adt/float.c --- b/src/backend/utils/adt/float.c *************** dacos(PG_FUNCTION_ARGS) *** 1524,1541 **** float8 arg1 = PG_GETARG_FLOAT8(0); float8 result; /* ! * We use errno here because the trigonometric functions are cyclic and ! * hard to check for underflow. */ ! errno = 0; ! result = acos(arg1); ! if (errno != 0) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("input is out of range"))); ! CHECKFLOATVAL(result, isinf(arg1), true); PG_RETURN_FLOAT8(result); } --- 1524,1546 ---- float8 arg1 = PG_GETARG_FLOAT8(0); float8 result; + /* Per the POSIX spec, return NaN if the input is NaN */ + if (isnan(arg1)) + PG_RETURN_FLOAT8(get_float8_nan()); + /* ! * The principal branch of the inverse cosine function maps values in the ! * range [-1, 1] to values in the range [0, Pi], so we should reject any ! * inputs outside that range and the result will always be finite. */ ! if (arg1 < -1.0 || arg1 > 1.0) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("input is out of range"))); ! result = acos(arg1); ! ! CHECKFLOATVAL(result, false, true); PG_RETURN_FLOAT8(result); } *************** dasin(PG_FUNCTION_ARGS) *** 1549,1562 **** float8 arg1 = PG_GETARG_FLOAT8(0); float8 result; ! errno = 0; ! result = asin(arg1); ! if (errno != 0) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("input is out of range"))); ! CHECKFLOATVAL(result, isinf(arg1), true); PG_RETURN_FLOAT8(result); } --- 1554,1576 ---- float8 arg1 = PG_GETARG_FLOAT8(0); float8 result; ! /* Per the POSIX spec, return NaN if the input is NaN */ ! if (isnan(arg1)) ! PG_RETURN_FLOAT8(get_float8_nan()); ! ! /* ! * The principal branch of the inverse sine function maps values in the ! * range [-1, 1] to values in the range [-Pi/2, Pi/2], so we should reject ! * any inputs outside that range and the result will always be finite. ! */ ! if (arg1 < -1.0 || arg1 > 1.0) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("input is out of range"))); ! result = asin(arg1); ! ! CHECKFLOATVAL(result, false, true); PG_RETURN_FLOAT8(result); } *************** datan(PG_FUNCTION_ARGS) *** 1570,1583 **** float8 arg1 = PG_GETARG_FLOAT8(0); float8 result; ! errno = 0; result = atan(arg1); - if (errno != 0) - ereport(ERROR, - (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), - errmsg("input is out of range"))); ! CHECKFLOATVAL(result, isinf(arg1), true); PG_RETURN_FLOAT8(result); } --- 1584,1601 ---- float8 arg1 = PG_GETARG_FLOAT8(0); float8 result; ! /* Per the POSIX spec, return NaN if the input is NaN */ ! if (isnan(arg1)) ! PG_RETURN_FLOAT8(get_float8_nan()); ! ! /* ! * The principal branch of the inverse tangent function maps all inputs to ! * values in the range [-Pi/2, Pi/2], so the result should always be ! * finite, even if the input is infinite. ! */ result = atan(arg1); ! CHECKFLOATVAL(result, false, true); PG_RETURN_FLOAT8(result); } *************** datan2(PG_FUNCTION_ARGS) *** 1592,1605 **** float8 arg2 = PG_GETARG_FLOAT8(1); float8 result; ! errno = 0; result = atan2(arg1, arg2); - if (errno != 0) - ereport(ERROR, - (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), - errmsg("input is out of range"))); ! CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true); PG_RETURN_FLOAT8(result); } --- 1610,1626 ---- float8 arg2 = PG_GETARG_FLOAT8(1); float8 result; ! /* Per the POSIX spec, return NaN if either input is NaN */ ! if (isnan(arg1) || isnan(arg2)) ! PG_RETURN_FLOAT8(get_float8_nan()); ! ! /* ! * atan2 maps all inputs to values in the range [-Pi, Pi], so the result ! * should always be finite, even if the inputs are infinite. ! */ result = atan2(arg1, arg2); ! CHECKFLOATVAL(result, false, true); PG_RETURN_FLOAT8(result); } *************** dcos(PG_FUNCTION_ARGS) *** 1613,1626 **** float8 arg1 = PG_GETARG_FLOAT8(0); float8 result; errno = 0; result = cos(arg1); ! if (errno != 0) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("input is out of range"))); ! CHECKFLOATVAL(result, isinf(arg1), true); PG_RETURN_FLOAT8(result); } --- 1634,1660 ---- float8 arg1 = PG_GETARG_FLOAT8(0); float8 result; + /* Per the POSIX spec, return NaN if the input is NaN */ + if (isnan(arg1)) + PG_RETURN_FLOAT8(get_float8_nan()); + + /* + * The trigonometric functions are periodic and so should work for all + * finite inputs, but it's possible that some platforms may have a more + * limited range, so we use errno to detect other out-of-range inputs. + * + * For infinite inputs, POSIX specifies that the trigonometric functions + * should return errno == EDOM, but not all platforms conform to that, so + * we explicitly test for infinite inputs if errno is not set. + */ errno = 0; result = cos(arg1); ! if (errno != 0 || isinf(arg1)) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("input is out of range"))); ! CHECKFLOATVAL(result, false /* result is always finite */ , true); PG_RETURN_FLOAT8(result); } *************** dcot(PG_FUNCTION_ARGS) *** 1634,1648 **** float8 arg1 = PG_GETARG_FLOAT8(0); float8 result; 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; ! CHECKFLOATVAL(result, true /* cotan(pi/2) == inf */ , true); PG_RETURN_FLOAT8(result); } --- 1668,1687 ---- float8 arg1 = PG_GETARG_FLOAT8(0); float8 result; + /* Per the POSIX spec, return NaN if the input is NaN */ + if (isnan(arg1)) + PG_RETURN_FLOAT8(get_float8_nan()); + + /* Be sure to throw an error if the input is infinite --- see dcos */ errno = 0; result = tan(arg1); ! if (errno != 0 || isinf(arg1)) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("input is out of range"))); result = 1.0 / result; ! CHECKFLOATVAL(result, true /* cot(0) == Inf */ , true); PG_RETURN_FLOAT8(result); } *************** dsin(PG_FUNCTION_ARGS) *** 1656,1669 **** float8 arg1 = PG_GETARG_FLOAT8(0); float8 result; errno = 0; result = sin(arg1); ! if (errno != 0) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("input is out of range"))); ! CHECKFLOATVAL(result, isinf(arg1), true); PG_RETURN_FLOAT8(result); } --- 1695,1713 ---- float8 arg1 = PG_GETARG_FLOAT8(0); float8 result; + /* Per the POSIX spec, return NaN if the input is NaN */ + if (isnan(arg1)) + PG_RETURN_FLOAT8(get_float8_nan()); + + /* Be sure to throw an error if the input is infinite --- see dcos */ errno = 0; result = sin(arg1); ! if (errno != 0 || isinf(arg1)) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("input is out of range"))); ! CHECKFLOATVAL(result, false /* result is always finite */ , true); PG_RETURN_FLOAT8(result); } *************** dtan(PG_FUNCTION_ARGS) *** 1677,1685 **** float8 arg1 = PG_GETARG_FLOAT8(0); float8 result; errno = 0; result = tan(arg1); ! if (errno != 0) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("input is out of range"))); --- 1721,1734 ---- float8 arg1 = PG_GETARG_FLOAT8(0); float8 result; + /* Per the POSIX spec, return NaN if the input is NaN */ + if (isnan(arg1)) + PG_RETURN_FLOAT8(get_float8_nan()); + + /* Be sure to throw an error if the input is infinite --- see dcos */ errno = 0; result = tan(arg1); ! if (errno != 0 || isinf(arg1)) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("input is out of range")));