Dennis Bjorklund <[EMAIL PROTECTED]> writes:
> In C one can set a signal handler to catch floating point exceptions
> (SIGFPE). Without a handler you can get NaN and Infinity as the
> result of mathematical operations.
Okay, I think this would be a reasonable set of behavior:
- define a new GUC var that controls how exceptional floating
point values (NaN, inf, -inf) are handled.
- by default, we still raise an error when a floating point
operation results in NaN / inf / etc.; if the GUC var is toggled
from its default value, no error is raised. This preserves
backward compatibility with applications that expect floating
point overflow to be reported, for example.
- that also means that, by default, we should reject 'NaN',
'Infinity', and '-Infinity' as input to float4/float8: if these
values are illegal as the result of FP operations by default, it
seems only logical to disallow them as input to the FP types.
Does that sound ok?
Unfortunately, I have more important things that I need to get wrapped
up in time for 7.5, so I can't finish this now. Dennis, would you like
to implement this?
Finally, I've attached a revised patch for 'Infinity' input to float4
and float8: this avoids breaking the regression tests by only allowing
'Infinity' and '-Infinity' as input, not as a legal result of FP
operations. This is obviously incomplete, as discussed above, but it
might be a good starting point. Should I commit this?
-Neil
Index: doc/src/sgml/syntax.sgml
===================================================================
RCS file: /var/lib/cvs/pgsql-server/doc/src/sgml/syntax.sgml,v
retrieving revision 1.89
diff -c -r1.89 syntax.sgml
*** a/doc/src/sgml/syntax.sgml 29 Nov 2003 19:51:37 -0000 1.89
--- b/doc/src/sgml/syntax.sgml 11 Mar 2004 21:18:57 -0000
***************
*** 359,364 ****
--- 359,382 ----
</literallayout>
</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 represnt the 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</>, and the
+ integral types do not allow any of these constants. These
+ constants are treated without sensitivity to case. These values
+ should be enclosed in single quotes.
+ </para>
+
<para>
<indexterm><primary>integer</primary></indexterm>
<indexterm><primary>bigint</primary></indexterm>
Index: src/backend/utils/adt/float.c
===================================================================
RCS file: /var/lib/cvs/pgsql-server/src/backend/utils/adt/float.c,v
retrieving revision 1.98
diff -c -r1.98 float.c
*** a/src/backend/utils/adt/float.c 11 Mar 2004 02:11:13 -0000 1.98
--- b/src/backend/utils/adt/float.c 11 Mar 2004 20:53:15 -0000
***************
*** 114,134 ****
/*
! * check to see if a float4 val is outside of
! * the FLOAT4_MIN, FLOAT4_MAX bounds.
*
! * raise an ereport warning 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),
--- 114,127 ----
/*
! * check to see if a float4 val is outside of the FLOAT4_MIN,
! * FLOAT4_MAX bounds.
*
! * raise an ereport() error if it is
! */
static void
CheckFloat4Val(double val)
{
if (fabs(val) > FLOAT4_MAX)
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
***************
*** 137,163 ****
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.
*
! * 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),
--- 130,146 ----
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("type \"real\" value out of range: underflow")));
}
/*
! * check to see if a float8 val is outside of the FLOAT8_MIN,
! * FLOAT8_MAX bounds.
*
! * raise an ereport() error if it is
*/
static void
CheckFloat8Val(double val)
{
if (fabs(val) > FLOAT8_MAX)
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
***************
*** 166,172 ****
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("type \"double precision\" value out of range: underflow")));
- #endif /* UNSAFE_FLOATS */
}
/*
--- 149,154 ----
***************
*** 201,210 ****
* 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')
{
--- 183,188 ----
***************
*** 217,222 ****
--- 195,204 ----
}
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,245 ****
* if we get here, we have a legal double, still need to check to see
* if it's a legal float
*/
! CheckFloat4Val(val);
PG_RETURN_FLOAT4((float4) val);
}
--- 221,228 ----
* if we get here, we have a legal double, still need to check to see
* if it's a legal float
*/
! if (!isinf(val))
! CheckFloat4Val(val);
PG_RETURN_FLOAT4((float4) val);
}
***************
*** 364,370 ****
errmsg("invalid input syntax for type double precision: \"%s\"",
num)));
! CheckFloat8Val(val);
PG_RETURN_FLOAT8(val);
}
--- 347,354 ----
errmsg("invalid input syntax for type double precision: \"%s\"",
num)));
! if (!isinf(val))
! CheckFloat8Val(val);
PG_RETURN_FLOAT8(val);
}
Index: src/include/pg_config_manual.h
===================================================================
RCS file: /var/lib/cvs/pgsql-server/src/include/pg_config_manual.h,v
retrieving revision 1.10
diff -c -r1.10 pg_config_manual.h
*** a/src/include/pg_config_manual.h 11 Feb 2004 22:55:26 -0000 1.10
--- b/src/include/pg_config_manual.h 11 Mar 2004 20:51:46 -0000
***************
*** 176,187 ****
#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
* 0..2^31-1, so we just hardwire this constant. We could do a
--- 176,181 ----
Index: src/test/regress/expected/float4.out
===================================================================
RCS file: /var/lib/cvs/pgsql-server/src/test/regress/expected/float4.out,v
retrieving revision 1.10
diff -c -r1.10 float4.out
*** a/src/test/regress/expected/float4.out 11 Mar 2004 02:11:13 -0000 1.10
--- b/src/test/regress/expected/float4.out 11 Mar 2004 21:04:58 -0000
***************
*** 50,58 ****
--- 50,88 ----
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
------+-------------
Index: src/test/regress/expected/float8.out
===================================================================
RCS file: /var/lib/cvs/pgsql-server/src/test/regress/expected/float8.out,v
retrieving revision 1.18
diff -c -r1.18 float8.out
*** a/src/test/regress/expected/float8.out 11 Mar 2004 02:11:13 -0000 1.18
--- b/src/test/regress/expected/float8.out 11 Mar 2004 21:04:56 -0000
***************
*** 50,58 ****
--- 50,88 ----
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
------+----------------------
Index: src/test/regress/sql/float4.sql
===================================================================
RCS file: /var/lib/cvs/pgsql-server/src/test/regress/sql/float4.sql,v
retrieving revision 1.5
diff -c -r1.5 float4.sql
*** a/src/test/regress/sql/float4.sql 11 Mar 2004 02:11:13 -0000 1.5
--- b/src/test/regress/sql/float4.sql 11 Mar 2004 20:51:46 -0000
***************
*** 29,36 ****
--- 29,45 ----
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.*;
Index: src/test/regress/sql/float8.sql
===================================================================
RCS file: /var/lib/cvs/pgsql-server/src/test/regress/sql/float8.sql,v
retrieving revision 1.9
diff -c -r1.9 float8.sql
*** a/src/test/regress/sql/float8.sql 11 Mar 2004 02:11:13 -0000 1.9
--- b/src/test/regress/sql/float8.sql 11 Mar 2004 20:51:46 -0000
***************
*** 29,36 ****
--- 29,44 ----
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.*;
---------------------------(end of broadcast)---------------------------
TIP 1: subscribe and unsubscribe commands go to [EMAIL PROTECTED]