From: Neil Conway Date: Fri, 12 Mar 2004 00:25:43 +0000 (+0000) Subject: Allow 'Infinity' and '-Infinity' as input to the float4 and float8 X-Git-Tag: REL8_0_0BETA1~1019 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=bfd6f52b0e0f1c1d579bf385dedfebca229dfcf5;p=postgresql Allow 'Infinity' and '-Infinity' as input to the float4 and float8 types. Update the regression tests and the documentation to reflect this. Remove the UNSAFE_FLOATS #ifdef. This is only half the story: we still unconditionally reject floating point operations that result in +/- infinity. See recent thread on -hackers for more information. --- diff --git a/doc/src/sgml/syntax.sgml b/doc/src/sgml/syntax.sgml index 5f82a78485..c6093b8463 100644 --- a/doc/src/sgml/syntax.sgml +++ b/doc/src/sgml/syntax.sgml @@ -1,5 +1,5 @@ @@ -359,6 +359,23 @@ SELECT 'foo' 'bar'; + + In addition, there are several special constant values that are + accepted as numeric constants. The float4 and + float8 types allow the following special constants: + +Infinity +-Infinity +NaN + + These represent the IEEE 754 special values + infinity, negative infinity, and + not-a-number, respectively. The + numeric type only allows NaN, whereas + the integral types do not allow any of these constants. Note that + these constants are recognized in a case-insensitive manner. + + integer bigint diff --git a/src/backend/utils/adt/float.c b/src/backend/utils/adt/float.c index 2707c83fd6..aed643d862 100644 --- a/src/backend/utils/adt/float.c +++ b/src/backend/utils/adt/float.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/float.c,v 1.98 2004/03/11 02:11:13 neilc Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/float.c,v 1.99 2004/03/12 00:25:40 neilc Exp $ * *------------------------------------------------------------------------- */ @@ -114,21 +114,14 @@ static int float8_cmp_internal(float8 a, float8 b); /* - * check to see if a float4 val is outside of - * the FLOAT4_MIN, FLOAT4_MAX bounds. + * check to see if a float4 val is outside of the FLOAT4_MIN, + * FLOAT4_MAX bounds. * - * raise an ereport warning if it is -*/ + * raise an ereport() error if it is + */ static void CheckFloat4Val(double val) { - /* - * defining unsafe floats's will make float4 and float8 ops faster at - * the cost of safety, of course! - */ -#ifdef UNSAFE_FLOATS - return; -#else if (fabs(val) > FLOAT4_MAX) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), @@ -137,27 +130,17 @@ CheckFloat4Val(double val) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("type \"real\" value out of range: underflow"))); - - return; -#endif /* UNSAFE_FLOATS */ } /* - * check to see if a float8 val is outside of - * the FLOAT8_MIN, FLOAT8_MAX bounds. + * check to see if a float8 val is outside of the FLOAT8_MIN, + * FLOAT8_MAX bounds. * - * raise an ereport error if it is + * raise an ereport() error if it is */ static void CheckFloat8Val(double val) { - /* - * defining unsafe floats's will make float4 and float8 ops faster at - * the cost of safety, of course! - */ -#ifdef UNSAFE_FLOATS - return; -#else if (fabs(val) > FLOAT8_MAX) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), @@ -166,7 +149,6 @@ CheckFloat8Val(double val) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("type \"double precision\" value out of range: underflow"))); -#endif /* UNSAFE_FLOATS */ } /* @@ -201,10 +183,6 @@ float4in(PG_FUNCTION_ARGS) * empty strings, but emit a warning noting that the feature * is deprecated. In 7.6+, the warning should be replaced by * an error. - * - * XXX we should accept "Infinity" and "-Infinity" too, but - * what are the correct values to assign? HUGE_VAL will - * provoke an error from CheckFloat4Val. */ if (*num == '\0') { @@ -217,6 +195,10 @@ float4in(PG_FUNCTION_ARGS) } else if (strcasecmp(num, "NaN") == 0) val = NAN; + else if (strcasecmp(num, "Infinity") == 0) + val = HUGE_VAL; + else if (strcasecmp(num, "-Infinity") == 0) + val = -HUGE_VAL; else ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), @@ -239,7 +221,8 @@ float4in(PG_FUNCTION_ARGS) * if we get here, we have a legal double, still need to check to see * if it's a legal float */ - CheckFloat4Val(val); + if (!isinf(val)) + CheckFloat4Val(val); PG_RETURN_FLOAT4((float4) val); } @@ -364,7 +347,8 @@ float8in(PG_FUNCTION_ARGS) errmsg("invalid input syntax for type double precision: \"%s\"", num))); - CheckFloat8Val(val); + if (!isinf(val)) + CheckFloat8Val(val); PG_RETURN_FLOAT8(val); } diff --git a/src/include/pg_config_manual.h b/src/include/pg_config_manual.h index 8226c6d5cf..6fcf38ec7b 100644 --- a/src/include/pg_config_manual.h +++ b/src/include/pg_config_manual.h @@ -6,7 +6,7 @@ * for developers. If you edit any of these, be sure to do a *full* * rebuild (and an initdb if noted). * - * $PostgreSQL: pgsql/src/include/pg_config_manual.h,v 1.10 2004/02/11 22:55:26 tgl Exp $ + * $PostgreSQL: pgsql/src/include/pg_config_manual.h,v 1.11 2004/03/12 00:25:40 neilc Exp $ *------------------------------------------------------------------------ */ @@ -175,12 +175,6 @@ */ #define DEFAULT_PGSOCKET_DIR "/tmp" -/* - * Defining this will make float4 and float8 operations faster by - * suppressing overflow/underflow checks. - */ -/* #define UNSAFE_FLOATS */ - /* * The random() function is expected to yield values between 0 and * MAX_RANDOM_VALUE. Currently, all known implementations yield diff --git a/src/test/regress/expected/float4.out b/src/test/regress/expected/float4.out index 124b7c378c..e4d460359f 100644 --- a/src/test/regress/expected/float4.out +++ b/src/test/regress/expected/float4.out @@ -50,9 +50,39 @@ SELECT ' NAN '::float4; NaN (1 row) +SELECT 'infinity'::float4; + float4 +---------- + Infinity +(1 row) + +SELECT ' -INFINiTY '::float4; + float4 +----------- + -Infinity +(1 row) + -- bad special inputs SELECT 'N A N'::float4; ERROR: invalid input syntax for type real: "N A N" +SELECT 'NaN x'::float4; +ERROR: invalid input syntax for type real: "NaN x" +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? +---------- + NaN +(1 row) + +SELECT 'nan'::float4 / 'nan'::float4; + ?column? +---------- + NaN +(1 row) + SELECT '' AS five, FLOAT4_TBL.*; five | f1 ------+------------- diff --git a/src/test/regress/expected/float8.out b/src/test/regress/expected/float8.out index 89e2bbf902..798a67c04f 100644 --- a/src/test/regress/expected/float8.out +++ b/src/test/regress/expected/float8.out @@ -50,9 +50,39 @@ SELECT ' NAN '::float8; NaN (1 row) +SELECT 'infinity'::float8; + float8 +---------- + Infinity +(1 row) + +SELECT ' -INFINiTY '::float8; + float8 +----------- + -Infinity +(1 row) + -- bad special inputs SELECT 'N A N'::float8; ERROR: invalid input syntax for type double precision: "N A N" +SELECT 'NaN x'::float8; +ERROR: invalid input syntax for type double precision: "NaN x" +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? +---------- + NaN +(1 row) + +SELECT 'nan'::float8 / 'nan'::float8; + ?column? +---------- + NaN +(1 row) + SELECT '' AS five, FLOAT8_TBL.*; five | f1 ------+---------------------- diff --git a/src/test/regress/sql/float4.sql b/src/test/regress/sql/float4.sql index b7b64f2e50..a7147409ec 100644 --- a/src/test/regress/sql/float4.sql +++ b/src/test/regress/sql/float4.sql @@ -29,8 +29,17 @@ INSERT INTO FLOAT4_TBL(f1) VALUES ('123 5'); SELECT 'NaN'::float4; SELECT 'nan'::float4; SELECT ' NAN '::float4; +SELECT 'infinity'::float4; +SELECT ' -INFINiTY '::float4; -- bad special inputs SELECT 'N A N'::float4; +SELECT 'NaN x'::float4; +SELECT ' INFINITY x'::float4; + +SELECT 'Infinity'::float4 + 100.0; +SELECT 'Infinity'::float4 / 'Infinity'::float4; +SELECT 'nan'::float4 / 'nan'::float4; + SELECT '' AS five, FLOAT4_TBL.*; diff --git a/src/test/regress/sql/float8.sql b/src/test/regress/sql/float8.sql index 1e5e8ad430..593df68a32 100644 --- a/src/test/regress/sql/float8.sql +++ b/src/test/regress/sql/float8.sql @@ -29,8 +29,16 @@ INSERT INTO FLOAT8_TBL(f1) VALUES ('123 5'); SELECT 'NaN'::float8; SELECT 'nan'::float8; SELECT ' NAN '::float8; +SELECT 'infinity'::float8; +SELECT ' -INFINiTY '::float8; -- bad special inputs SELECT 'N A N'::float8; +SELECT 'NaN x'::float8; +SELECT ' INFINITY x'::float8; + +SELECT 'Infinity'::float8 + 100.0; +SELECT 'Infinity'::float8 / 'Infinity'::float8; +SELECT 'nan'::float8 / 'nan'::float8; SELECT '' AS five, FLOAT8_TBL.*;