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]

Reply via email to