Commit bfd6f52b authored by Neil Conway's avatar Neil Conway

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.
parent fe6e9221
<!-- <!--
$PostgreSQL: pgsql/doc/src/sgml/syntax.sgml,v 1.89 2003/11/29 19:51:37 pgsql Exp $ $PostgreSQL: pgsql/doc/src/sgml/syntax.sgml,v 1.90 2004/03/12 00:25:40 neilc Exp $
--> -->
<chapter id="sql-syntax"> <chapter id="sql-syntax">
...@@ -359,6 +359,23 @@ SELECT 'foo' 'bar'; ...@@ -359,6 +359,23 @@ SELECT 'foo' 'bar';
</literallayout> </literallayout>
</para> </para>
<para>
In addition, there are several special constant values that are
accepted as numeric constants. The <type>float4</type> and
<type>float8</type> types allow the following special constants:
<literallayout>
Infinity
-Infinity
NaN
</literallayout>
These represent the IEEE 754 special values
<quote>infinity</quote>, <quote>negative infinity</quote>, and
<quote>not-a-number</quote>, respectively. The
<type>numeric</type> type only allows <literal>NaN</>, whereas
the integral types do not allow any of these constants. Note that
these constants are recognized in a case-insensitive manner.
</para>
<para> <para>
<indexterm><primary>integer</primary></indexterm> <indexterm><primary>integer</primary></indexterm>
<indexterm><primary>bigint</primary></indexterm> <indexterm><primary>bigint</primary></indexterm>
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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); ...@@ -114,21 +114,14 @@ static int float8_cmp_internal(float8 a, float8 b);
/* /*
* check to see if a float4 val is outside of * check to see if a float4 val is outside of the FLOAT4_MIN,
* the FLOAT4_MIN, FLOAT4_MAX bounds. * FLOAT4_MAX bounds.
* *
* raise an ereport warning if it is * raise an ereport() error if it is
*/ */
static void static void
CheckFloat4Val(double val) 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) if (fabs(val) > FLOAT4_MAX)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
...@@ -137,27 +130,17 @@ CheckFloat4Val(double val) ...@@ -137,27 +130,17 @@ CheckFloat4Val(double val)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("type \"real\" value out of range: underflow"))); errmsg("type \"real\" value out of range: underflow")));
return;
#endif /* UNSAFE_FLOATS */
} }
/* /*
* check to see if a float8 val is outside of * check to see if a float8 val is outside of the FLOAT8_MIN,
* the FLOAT8_MIN, FLOAT8_MAX bounds. * FLOAT8_MAX bounds.
* *
* raise an ereport error if it is * raise an ereport() error if it is
*/ */
static void static void
CheckFloat8Val(double val) 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) if (fabs(val) > FLOAT8_MAX)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
...@@ -166,7 +149,6 @@ CheckFloat8Val(double val) ...@@ -166,7 +149,6 @@ CheckFloat8Val(double val)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("type \"double precision\" value out of range: underflow"))); errmsg("type \"double precision\" value out of range: underflow")));
#endif /* UNSAFE_FLOATS */
} }
/* /*
...@@ -201,10 +183,6 @@ float4in(PG_FUNCTION_ARGS) ...@@ -201,10 +183,6 @@ float4in(PG_FUNCTION_ARGS)
* empty strings, but emit a warning noting that the feature * empty strings, but emit a warning noting that the feature
* is deprecated. In 7.6+, the warning should be replaced by * is deprecated. In 7.6+, the warning should be replaced by
* an error. * 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') if (*num == '\0')
{ {
...@@ -217,6 +195,10 @@ float4in(PG_FUNCTION_ARGS) ...@@ -217,6 +195,10 @@ float4in(PG_FUNCTION_ARGS)
} }
else if (strcasecmp(num, "NaN") == 0) else if (strcasecmp(num, "NaN") == 0)
val = NAN; val = NAN;
else if (strcasecmp(num, "Infinity") == 0)
val = HUGE_VAL;
else if (strcasecmp(num, "-Infinity") == 0)
val = -HUGE_VAL;
else else
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
...@@ -239,6 +221,7 @@ float4in(PG_FUNCTION_ARGS) ...@@ -239,6 +221,7 @@ float4in(PG_FUNCTION_ARGS)
* if we get here, we have a legal double, still need to check to see * if we get here, we have a legal double, still need to check to see
* if it's a legal float * if it's a legal float
*/ */
if (!isinf(val))
CheckFloat4Val(val); CheckFloat4Val(val);
PG_RETURN_FLOAT4((float4) val); PG_RETURN_FLOAT4((float4) val);
...@@ -364,6 +347,7 @@ float8in(PG_FUNCTION_ARGS) ...@@ -364,6 +347,7 @@ float8in(PG_FUNCTION_ARGS)
errmsg("invalid input syntax for type double precision: \"%s\"", errmsg("invalid input syntax for type double precision: \"%s\"",
num))); num)));
if (!isinf(val))
CheckFloat8Val(val); CheckFloat8Val(val);
PG_RETURN_FLOAT8(val); PG_RETURN_FLOAT8(val);
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* for developers. If you edit any of these, be sure to do a *full* * for developers. If you edit any of these, be sure to do a *full*
* rebuild (and an initdb if noted). * 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 @@ ...@@ -175,12 +175,6 @@
*/ */
#define DEFAULT_PGSOCKET_DIR "/tmp" #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 * The random() function is expected to yield values between 0 and
* MAX_RANDOM_VALUE. Currently, all known implementations yield * MAX_RANDOM_VALUE. Currently, all known implementations yield
......
...@@ -50,9 +50,39 @@ SELECT ' NAN '::float4; ...@@ -50,9 +50,39 @@ SELECT ' NAN '::float4;
NaN NaN
(1 row) (1 row)
SELECT 'infinity'::float4;
float4
----------
Infinity
(1 row)
SELECT ' -INFINiTY '::float4;
float4
-----------
-Infinity
(1 row)
-- bad special inputs -- bad special inputs
SELECT 'N A N'::float4; SELECT 'N A N'::float4;
ERROR: invalid input syntax for type real: "N A N" 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.*; SELECT '' AS five, FLOAT4_TBL.*;
five | f1 five | f1
------+------------- ------+-------------
......
...@@ -50,9 +50,39 @@ SELECT ' NAN '::float8; ...@@ -50,9 +50,39 @@ SELECT ' NAN '::float8;
NaN NaN
(1 row) (1 row)
SELECT 'infinity'::float8;
float8
----------
Infinity
(1 row)
SELECT ' -INFINiTY '::float8;
float8
-----------
-Infinity
(1 row)
-- bad special inputs -- bad special inputs
SELECT 'N A N'::float8; SELECT 'N A N'::float8;
ERROR: invalid input syntax for type double precision: "N A N" 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.*; SELECT '' AS five, FLOAT8_TBL.*;
five | f1 five | f1
------+---------------------- ------+----------------------
......
...@@ -29,8 +29,17 @@ INSERT INTO FLOAT4_TBL(f1) VALUES ('123 5'); ...@@ -29,8 +29,17 @@ INSERT INTO FLOAT4_TBL(f1) VALUES ('123 5');
SELECT 'NaN'::float4; SELECT 'NaN'::float4;
SELECT 'nan'::float4; SELECT 'nan'::float4;
SELECT ' NAN '::float4; SELECT ' NAN '::float4;
SELECT 'infinity'::float4;
SELECT ' -INFINiTY '::float4;
-- bad special inputs -- bad special inputs
SELECT 'N A N'::float4; 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.*; SELECT '' AS five, FLOAT4_TBL.*;
......
...@@ -29,8 +29,16 @@ INSERT INTO FLOAT8_TBL(f1) VALUES ('123 5'); ...@@ -29,8 +29,16 @@ INSERT INTO FLOAT8_TBL(f1) VALUES ('123 5');
SELECT 'NaN'::float8; SELECT 'NaN'::float8;
SELECT 'nan'::float8; SELECT 'nan'::float8;
SELECT ' NAN '::float8; SELECT ' NAN '::float8;
SELECT 'infinity'::float8;
SELECT ' -INFINiTY '::float8;
-- bad special inputs -- bad special inputs
SELECT 'N A N'::float8; 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.*; SELECT '' AS five, FLOAT8_TBL.*;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment