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]