diff --git a/src/backend/utils/adt/float.c b/src/backend/utils/adt/float.c index 88215d910a..f5b20a5a46 100644 --- a/src/backend/utils/adt/float.c +++ b/src/backend/utils/adt/float.c @@ -1548,6 +1548,25 @@ dpow(PG_FUNCTION_ARGS) float8 arg2 = PG_GETARG_FLOAT8(1); float8 result; + /* + * The POSIX spec says that NaN ^ 0 = 1, and 1 ^ NaN = 1, while all other + * cases with NaN inputs yield NaN (with no error). Many older platforms + * get one or more of these cases wrong, so deal with them via explicit + * logic rather than trusting pow(3). + */ + if (isnan(arg1)) + { + if (isnan(arg2) || arg2 != 0.0) + PG_RETURN_FLOAT8(get_float8_nan()); + PG_RETURN_FLOAT8(1.0); + } + if (isnan(arg2)) + { + if (arg1 != 1.0) + PG_RETURN_FLOAT8(get_float8_nan()); + PG_RETURN_FLOAT8(1.0); + } + /* * The SQL spec requires that we emit a particular SQLSTATE error code for * certain error conditions. Specifically, we don't return a @@ -1569,12 +1588,11 @@ dpow(PG_FUNCTION_ARGS) * and result == NaN for negative arg1 and very large arg2 (they must be * using something different from our floor() test to decide it's * invalid). Other platforms (HPPA) return errno == ERANGE and a large - * (HUGE_VAL) but finite result to signal overflow. Also, some versions - * of MSVC return errno == EDOM and result == NaN for NaN inputs. + * (HUGE_VAL) but finite result to signal overflow. */ errno = 0; result = pow(arg1, arg2); - if (errno == EDOM && isnan(result) && !isnan(arg1) && !isnan(arg2)) + if (errno == EDOM && isnan(result)) { if ((fabs(arg1) > 1 && arg2 >= 0) || (fabs(arg1) < 1 && arg2 < 0)) /* The sign of Inf is not significant in this case. */ diff --git a/src/test/regress/expected/float8-exp-three-digits-win32.out b/src/test/regress/expected/float8-exp-three-digits-win32.out index 3fe50b4bf0..3896cdec72 100644 --- a/src/test/regress/expected/float8-exp-three-digits-win32.out +++ b/src/test/regress/expected/float8-exp-three-digits-win32.out @@ -358,6 +358,12 @@ SELECT power(float8 'NaN', float8 'NaN'); NaN (1 row) +SELECT power(float8 '-1', float8 'NaN'); + power +------- + NaN +(1 row) + SELECT power(float8 '1', float8 'NaN'); power ------- diff --git a/src/test/regress/expected/float8-small-is-zero.out b/src/test/regress/expected/float8-small-is-zero.out index 46adbe1c4b..f8e09390f5 100644 --- a/src/test/regress/expected/float8-small-is-zero.out +++ b/src/test/regress/expected/float8-small-is-zero.out @@ -362,6 +362,12 @@ SELECT power(float8 'NaN', float8 'NaN'); NaN (1 row) +SELECT power(float8 '-1', float8 'NaN'); + power +------- + NaN +(1 row) + SELECT power(float8 '1', float8 'NaN'); power ------- diff --git a/src/test/regress/expected/float8-small-is-zero_1.out b/src/test/regress/expected/float8-small-is-zero_1.out index f215eede10..ebfec4cdb6 100644 --- a/src/test/regress/expected/float8-small-is-zero_1.out +++ b/src/test/regress/expected/float8-small-is-zero_1.out @@ -362,6 +362,12 @@ SELECT power(float8 'NaN', float8 'NaN'); NaN (1 row) +SELECT power(float8 '-1', float8 'NaN'); + power +------- + NaN +(1 row) + SELECT power(float8 '1', float8 'NaN'); power ------- diff --git a/src/test/regress/expected/float8.out b/src/test/regress/expected/float8.out index 7159e78d4a..b05831d45c 100644 --- a/src/test/regress/expected/float8.out +++ b/src/test/regress/expected/float8.out @@ -358,6 +358,12 @@ SELECT power(float8 'NaN', float8 'NaN'); NaN (1 row) +SELECT power(float8 '-1', float8 'NaN'); + power +------- + NaN +(1 row) + SELECT power(float8 '1', float8 'NaN'); power ------- diff --git a/src/test/regress/sql/float8.sql b/src/test/regress/sql/float8.sql index 5510fe9d34..eeebddd4b7 100644 --- a/src/test/regress/sql/float8.sql +++ b/src/test/regress/sql/float8.sql @@ -111,6 +111,7 @@ SELECT power(float8 '144', float8 '0.5'); SELECT power(float8 'NaN', float8 '0.5'); SELECT power(float8 '144', float8 'NaN'); SELECT power(float8 'NaN', float8 'NaN'); +SELECT power(float8 '-1', float8 'NaN'); SELECT power(float8 '1', float8 'NaN'); SELECT power(float8 'NaN', float8 '0');