From 49edffbe0f16b94e31358fe173ed0ace8e7bb8ef Mon Sep 17 00:00:00 2001 From: l00584793 Date: Tue, 8 Sep 2020 11:17:37 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AF=B9=E6=89=80=E4=BF=AE=E6=94=B9=E5=87=BD?= =?UTF-8?q?=E6=95=B0=E4=BB=8D=E5=AD=98=E5=9C=A8=E7=9A=84=E4=B8=80=E4=BA=9B?= =?UTF-8?q?=E9=97=AE=E9=A2=98=E8=BF=9B=E8=A1=8C=E4=BA=86=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=EF=BC=8C=E5=B9=B6=E6=9B=B4=E6=96=B0=E4=BA=86=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E7=94=A8=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/common/backend/utils/adt/float.cpp | 36 ++++++------- src/test/regress/expected/float8.out | 75 ++++++++++++++++++-------- src/test/regress/sql/float8.sql | 8 +++ 3 files changed, 80 insertions(+), 39 deletions(-) diff --git a/src/common/backend/utils/adt/float.cpp b/src/common/backend/utils/adt/float.cpp index d39784844..39c8785bd 100755 --- a/src/common/backend/utils/adt/float.cpp +++ b/src/common/backend/utils/adt/float.cpp @@ -1375,20 +1375,11 @@ Datum dpow(PG_FUNCTION_ARGS) float8 arg2 = PG_GETARG_FLOAT8(1); float8 result; - 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 + * divide-by-zero error code for 0 ^ -1. + */ if (arg1 == 0 && arg2 < 0) { ereport(ERROR, (errcode(ERRCODE_INVALID_ARGUMENT_FOR_POWER_FUNCTION), errmsg("zero raised to a negative power is undefined"))); @@ -1398,7 +1389,15 @@ Datum dpow(PG_FUNCTION_ARGS) ereport(ERROR, (errcode(ERRCODE_INVALID_ARGUMENT_FOR_POWER_FUNCTION), errmsg("a negative number raised to a non-integer power yields a complex result"))); } - + /* + * pow() sets errno only on some platforms, depending on whether it + * follows _IEEE_, _POSIX_, _XOPEN_, or _SVID_, so we try to avoid using + * errno. However, some platform/CPU combinations return errno == EDOM + * 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. + */ errno = 0; result = pow(arg1, arg2); if (errno == EDOM && isnan(result)) { @@ -1413,7 +1412,7 @@ Datum dpow(PG_FUNCTION_ARGS) } else if (errno == ERANGE && result != 0 && !isinf(result)) { result = get_float8_infinity(); } - CHECKFLOATVAL(result, isinf(arg1), true); + CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0); PG_RETURN_FLOAT8(result); } @@ -1576,6 +1575,7 @@ Datum dcos(PG_FUNCTION_ARGS) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("input is out of range"))); } + CHECKFLOATVAL(result, isinf(arg1), true); PG_RETURN_FLOAT8(result); } @@ -1597,7 +1597,7 @@ Datum dcot(PG_FUNCTION_ARGS) } result = 1.0 / result; - CHECKFLOATVAL(result, isinf(arg1), true); + CHECKFLOATVAL(result, true, true); PG_RETURN_FLOAT8(result); } @@ -1639,7 +1639,7 @@ Datum dtan(PG_FUNCTION_ARGS) if (errno != 0 || isinf(arg1)) { ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("input is out of range"))); } - CHECKFLOATVAL(result, isinf(arg1), true); + CHECKFLOATVAL(result, true, true); PG_RETURN_FLOAT8(result); } diff --git a/src/test/regress/expected/float8.out b/src/test/regress/expected/float8.out index cef602917..30e5a8d63 100644 --- a/src/test/regress/expected/float8.out +++ b/src/test/regress/expected/float8.out @@ -547,6 +547,36 @@ SELECT tan('1'); 1.5574077246549 (1 row) +SELECT cot('1'); + cot +------------------ + .642092615934331 +(1 row) + +SELECT sin('0'); + sin +----- + 0 +(1 row) + +SELECT cos('0'); + cos +----- + 1 +(1 row) + +SELECT tan('0'); + tan +----- + 0 +(1 row) + +SELECT cot('0'); + cot +---------- + Infinity +(1 row) + -- test Inf/NaN cases for functions SELECT sin('infinity'); ERROR: input is out of range @@ -584,6 +614,18 @@ SELECT tan('nan'); NaN (1 row) +SELECT cot('infinity'); +ERROR: input is out of range +CONTEXT: referenced column: cot +SELECT cot('-infinity'); +ERROR: input is out of range +CONTEXT: referenced column: cot +SELECT cot('nan'); + cot +----- + NaN +(1 row) + --test power SELECT power('0', '0'); power @@ -637,14 +679,14 @@ SELECT power('5', '2'); (1 row) SELECT power('5', 'infinity'); -ERROR: value out of range: overflow -CONTEXT: referenced column: power -SELECT power('5', '-infinity'); - power -------- - 0 + power +---------- + Infinity (1 row) +SELECT power('5', '-infinity'); +ERROR: value out of range: underflow +CONTEXT: referenced column: power SELECT power('5', 'nan'); power ------- @@ -676,11 +718,8 @@ SELECT power('infinity', 'infinity'); (1 row) SELECT power('infinity', '-infinity'); - power -------- - 0 -(1 row) - +ERROR: value out of range: underflow +CONTEXT: referenced column: power SELECT power('infinity', 'nan'); power ------- @@ -712,17 +751,11 @@ SELECT power('-infinity', 'infinity'); (1 row) SELECT power('-infinity', '-infinity'); - power -------- - 0 -(1 row) - +ERROR: value out of range: underflow +CONTEXT: referenced column: power SELECT power('-infinity', 'nan'); - power -------- - NaN -(1 row) - +ERROR: a negative number raised to a non-integer power yields a complex result +CONTEXT: referenced column: power SELECT power('nan', '0'); power ------- diff --git a/src/test/regress/sql/float8.sql b/src/test/regress/sql/float8.sql index 02af570f4..e6c1fefc9 100644 --- a/src/test/regress/sql/float8.sql +++ b/src/test/regress/sql/float8.sql @@ -185,6 +185,11 @@ SELECT '-9223372036854780000'::float8::int8; SELECT sin('1'); SELECT cos('1'); SELECT tan('1'); +SELECT cot('1'); +SELECT sin('0'); +SELECT cos('0'); +SELECT tan('0'); +SELECT cot('0'); -- test Inf/NaN cases for functions SELECT sin('infinity'); SELECT sin('-infinity'); @@ -195,6 +200,9 @@ SELECT cos('nan'); SELECT tan('infinity'); SELECT tan('-infinity'); SELECT tan('nan'); +SELECT cot('infinity'); +SELECT cot('-infinity'); +SELECT cot('nan'); --test power SELECT power('0', '0');