Bruce Momjian <[EMAIL PROTECTED]> writes:
> I am seeing the following regression failure for current CVS.  On my
> OS, BSD/OS 4.3, it seems once you hit Infinity, you can't negate it.

Actually, I suspect the problem is that isinf() on your platform
returns 1 for any infinity (rather than -1 for negative infinity and 1
for positive infinity). Some existing code in float4out() and
float8out() assumed that a positive return from isinf() indicated a
positive infinity, which is not per C99.

Anyway, Tom and I worked through this issue, and a couple other
portability problems with the recent float changes, via private
email. The current patch is attached -- Tom hasn't yet gotten back to
me on whether this fixes the problem for him on HPUX, but it fixes my
OS X box.

-Neil

Index: src/backend/utils/adt/float.c
===================================================================
RCS file: /var/lib/cvs/pgsql-server/src/backend/utils/adt/float.c,v
retrieving revision 1.99
diff -c -r1.99 float.c
*** a/src/backend/utils/adt/float.c	12 Mar 2004 00:25:40 -0000	1.99
--- b/src/backend/utils/adt/float.c	14 Mar 2004 01:07:21 -0000
***************
*** 109,117 ****
--- 109,138 ----
  
  static void CheckFloat4Val(double val);
  static void CheckFloat8Val(double val);
+ static int	is_infinite(double val);
  static int	float4_cmp_internal(float4 a, float4 b);
  static int	float8_cmp_internal(float8 a, float8 b);
  
+ /*
+  * Returns -1 if 'val' represents negative infinity, 1 if 'val'
+  * represents (positive) infinity, and 0 otherwise. On same platforms,
+  * this is equivalent to the isinf() macro, but not everywhere: C99
+  * does not specify that isinf() needs to distinguish between positive
+  * and negative infinity.
+  */
+ static int
+ is_infinite(double val)
+ {
+ 	int inf = isinf(val);
+ 
+ 	if (inf == 0)
+ 		return 0;
+ 
+ 	if (val > 0)
+ 		return 1;
+ 
+ 	return -1;
+ }
  
  /*
   * check to see if a float4 val is outside of the FLOAT4_MIN,
***************
*** 154,160 ****
  /*
   *		float4in		- converts "num" to float
   *						  restricted syntax:
!  *						  {<sp>} [+|-] {digit} [.{digit}] [<exp>]
   *						  where <sp> is a space, digit is 0-9,
   *						  <exp> is "e" or "E" followed by an integer.
   */
--- 175,182 ----
  /*
   *		float4in		- converts "num" to float
   *						  restricted syntax:
!  *						
!   {<sp>} [+|-] {digit} [.{digit}] [<exp>]
   *						  where <sp> is a space, digit is 0-9,
   *						  <exp> is "e" or "E" followed by an integer.
   */
***************
*** 162,209 ****
  float4in(PG_FUNCTION_ARGS)
  {
  	char	   *num = PG_GETARG_CSTRING(0);
  	double		val;
  	char	   *endptr;
  
  	errno = 0;
  	val = strtod(num, &endptr);
  
  	if (errno == ERANGE)
  		ereport(ERROR,
  				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
! 				 errmsg("\"%s\" is out of range for type real", num)));
  
  	if (num == endptr)
  	{
  		/*
! 		 * We didn't find anything that looks like a float in the input
! 		 *
! 		 * In releases prior to 7.5, we accepted an empty string as
! 		 * valid input (yielding a float8 of 0). In 7.5, we accept
! 		 * empty strings, but emit a warning noting that the feature
! 		 * is deprecated. In 7.6+, the warning should be replaced by
! 		 * an error.
  		 */
! 		if (*num == '\0')
  		{
- 			ereport(WARNING,
- 					(errcode(ERRCODE_WARNING_DEPRECATED_FEATURE),
- 					 errmsg("deprecated input syntax for type real: \"\""),
- 					 errdetail("This input will be rejected in "
- 							   "a future release of PostgreSQL.")));
- 			Assert(val == 0.0);
- 		}
- 		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),
  					 errmsg("invalid input syntax for type real: \"%s\"",
! 							num)));
  	}
  
  	/* skip trailing whitespace */
--- 184,261 ----
  float4in(PG_FUNCTION_ARGS)
  {
  	char	   *num = PG_GETARG_CSTRING(0);
+ 	char	   *orig_num;
  	double		val;
  	char	   *endptr;
  
+ 	/*
+ 	 * endptr points to the first character _after_ the sequence we
+ 	 * recognized as a valid floating point number. orig_num points to
+ 	 * the original input string.
+ 	 */
+ 	orig_num = num;
+ 
+ 	/*
+ 	 * Check for an empty-string input to begin with, to avoid
+ 	 * the vagaries of strtod() on different platforms.
+ 	 *
+ 	 * In releases prior to 7.5, we accepted an empty string as valid
+ 	 * input (yielding a float4 of 0). In 7.5, we accept empty
+ 	 * strings, but emit a warning noting that the feature is
+ 	 * deprecated. In 7.6+, the warning should be replaced by an
+ 	 * error.
+ 	 */
+ 	if (*num == '\0')
+ 	{
+ 		ereport(WARNING,
+ 				(errcode(ERRCODE_WARNING_DEPRECATED_FEATURE),
+ 				 errmsg("deprecated input syntax for type real: \"\""),
+ 				 errdetail("This input will be rejected in "
+ 						   "a future release of PostgreSQL.")));
+ 		PG_RETURN_FLOAT4((float4) 0.0);
+ 	}
+ 
+ 	/* skip leading whitespace */
+ 	while (*num != '\0' && isspace(*num))
+ 		num++;
+ 
  	errno = 0;
  	val = strtod(num, &endptr);
  
  	if (errno == ERANGE)
  		ereport(ERROR,
  				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
! 				 errmsg("\"%s\" is out of range for type real",
! 						orig_num)));
  
+ 	/* did we not see anything that looks like a double? */
  	if (num == endptr)
  	{
  		/*
! 		 * C99 requires that strtod() accept NaN and [-]Infinity, but
! 		 * not all platforms support that yet. Therefore, we check for
! 		 * these inputs ourselves.
  		 */
! 		if (strncasecmp(num, "NaN", 3) == 0)
  		{
  			val = NAN;
! 			endptr = num + 3;
! 		}
! 		else if (strncasecmp(num, "Infinity", 8) == 0)
! 		{
  			val = HUGE_VAL;
! 			endptr = num + 8;
! 		}
! 		else if (strncasecmp(num, "-Infinity", 9) == 0)
! 		{
  			val = -HUGE_VAL;
+ 			endptr = num + 9;
+ 		}
  		else
  			ereport(ERROR,
  					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
  					 errmsg("invalid input syntax for type real: \"%s\"",
! 							orig_num)));
  	}
  
  	/* skip trailing whitespace */
***************
*** 215,225 ****
  		ereport(ERROR,
  				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
  				 errmsg("invalid input syntax for type real: \"%s\"",
! 						num)));
  
  	/*
  	 * 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);
--- 267,277 ----
  		ereport(ERROR,
  				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
  				 errmsg("invalid input syntax for type real: \"%s\"",
! 						orig_num)));
  
  	/*
  	 * if we get here, we have a legal double, still need to check to see
! 	 * if it's a legal float4
  	 */
  	if (!isinf(val))
  		CheckFloat4Val(val);
***************
*** 236,257 ****
  {
  	float4		num = PG_GETARG_FLOAT4(0);
  	char	   *ascii = (char *) palloc(MAXFLOATWIDTH + 1);
- 	int			infflag;
- 	int			ndig;
  
  	if (isnan(num))
  		PG_RETURN_CSTRING(strcpy(ascii, "NaN"));
- 	infflag = isinf(num);
- 	if (infflag > 0)
- 		PG_RETURN_CSTRING(strcpy(ascii, "Infinity"));
- 	if (infflag < 0)
- 		PG_RETURN_CSTRING(strcpy(ascii, "-Infinity"));
- 
- 	ndig = FLT_DIG + extra_float_digits;
- 	if (ndig < 1)
- 		ndig = 1;
  
! 	sprintf(ascii, "%.*g", ndig, num);
  
  	PG_RETURN_CSTRING(ascii);
  }
--- 288,314 ----
  {
  	float4		num = PG_GETARG_FLOAT4(0);
  	char	   *ascii = (char *) palloc(MAXFLOATWIDTH + 1);
  
  	if (isnan(num))
  		PG_RETURN_CSTRING(strcpy(ascii, "NaN"));
  
! 	switch (is_infinite(num))
! 	{
! 		case 1:
! 			strcpy(ascii, "Infinity");
! 			break;
! 		case -1:
! 			strcpy(ascii, "-Infinity");
! 			break;
! 		default:
! 		{
! 			int ndig = FLT_DIG + extra_float_digits;
! 			if (ndig < 1)
! 				ndig = 1;
! 
! 			sprintf(ascii, "%.*g", ndig, num);
! 		}
! 	}
  
  	PG_RETURN_CSTRING(ascii);
  }
***************
*** 292,339 ****
  float8in(PG_FUNCTION_ARGS)
  {
  	char	   *num = PG_GETARG_CSTRING(0);
  	double		val;
  	char	   *endptr;
  
  	errno = 0;
  	val = strtod(num, &endptr);
  
  	if (errno == ERANGE)
  		ereport(ERROR,
  				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
! 				 errmsg("\"%s\" is out of range for type double precision", num)));
  
  	if (num == endptr)
  	{
  		/*
! 		 * We didn't find anything that looks like a float in the input
! 		 *
! 		 * In releases prior to 7.5, we accepted an empty string as
! 		 * valid input (yielding a float8 of 0). In 7.5, we accept
! 		 * empty strings, but emit a warning noting that the feature
! 		 * is deprecated. In 7.6+, the warning should be replaced by
! 		 * an error.
  		 */
! 		if (*num == '\0')
  		{
- 			ereport(WARNING,
- 					(errcode(ERRCODE_WARNING_DEPRECATED_FEATURE),
- 					 errmsg("deprecated input syntax for type double precision: \"\""),
- 					 errdetail("This input will be rejected in "
- 							   "a future release of PostgreSQL.")));
- 			Assert(val == 0.0);
- 		}
- 		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),
  					 errmsg("invalid input syntax for type double precision: \"%s\"",
! 							num)));
  	}
  
  	/* skip trailing whitespace */
--- 349,426 ----
  float8in(PG_FUNCTION_ARGS)
  {
  	char	   *num = PG_GETARG_CSTRING(0);
+ 	char	   *orig_num;
  	double		val;
  	char	   *endptr;
  
+ 	/*
+ 	 * endptr points to the first character _after_ the sequence we
+ 	 * recognized as a valid floating point number. orig_num points to
+ 	 * the original input string.
+ 	 */
+ 	orig_num = num;
+ 
+ 	/*
+ 	 * Check for an empty-string input to begin with, to avoid
+ 	 * the vagaries of strtod() on different platforms.
+ 	 *
+ 	 * In releases prior to 7.5, we accepted an empty string as valid
+ 	 * input (yielding a float8 of 0). In 7.5, we accept empty
+ 	 * strings, but emit a warning noting that the feature is
+ 	 * deprecated. In 7.6+, the warning should be replaced by an
+ 	 * error.
+ 	 */
+ 	if (*num == '\0')
+ 	{
+ 		ereport(WARNING,
+ 				(errcode(ERRCODE_WARNING_DEPRECATED_FEATURE),
+ 				 errmsg("deprecated input syntax for type double precision: \"\""),
+ 				 errdetail("This input will be rejected in "
+ 						   "a future release of PostgreSQL.")));
+ 		PG_RETURN_FLOAT8(0.0);
+ 	}
+ 
+ 	/* skip leading whitespace */
+ 	while (*num != '\0' && isspace(*num))
+ 		num++;
+ 
  	errno = 0;
  	val = strtod(num, &endptr);
  
  	if (errno == ERANGE)
  		ereport(ERROR,
  				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
! 				 errmsg("\"%s\" is out of range for type double precision",
! 						orig_num)));
  
+ 	/* did we not see anything that looks like a double? */
  	if (num == endptr)
  	{
  		/*
! 		 * C99 requires that strtod() accept NaN and [-]Infinity, but
! 		 * not all platforms support that yet. Therefore, we check for
! 		 * these inputs ourselves.
  		 */
! 		if (strncasecmp(num, "NaN", 3) == 0)
  		{
  			val = NAN;
! 			endptr = num + 3;
! 		}
! 		else if (strncasecmp(num, "Infinity", 8) == 0)
! 		{
  			val = HUGE_VAL;
! 			endptr = num + 8;
! 		}
! 		else if (strncasecmp(num, "-Infinity", 9) == 0)
! 		{
  			val = -HUGE_VAL;
+ 			endptr = num + 9;
+ 		}
  		else
  			ereport(ERROR,
  					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
  					 errmsg("invalid input syntax for type double precision: \"%s\"",
! 							orig_num)));
  	}
  
  	/* skip trailing whitespace */
***************
*** 345,351 ****
  		ereport(ERROR,
  				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
  				 errmsg("invalid input syntax for type double precision: \"%s\"",
! 						num)));
  
  	if (!isinf(val))
  		CheckFloat8Val(val);
--- 432,438 ----
  		ereport(ERROR,
  				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
  				 errmsg("invalid input syntax for type double precision: \"%s\"",
! 						orig_num)));
  
  	if (!isinf(val))
  		CheckFloat8Val(val);
***************
*** 362,383 ****
  {
  	float8		num = PG_GETARG_FLOAT8(0);
  	char	   *ascii = (char *) palloc(MAXDOUBLEWIDTH + 1);
- 	int			infflag;
- 	int			ndig;
  
  	if (isnan(num))
  		PG_RETURN_CSTRING(strcpy(ascii, "NaN"));
- 	infflag = isinf(num);
- 	if (infflag > 0)
- 		PG_RETURN_CSTRING(strcpy(ascii, "Infinity"));
- 	if (infflag < 0)
- 		PG_RETURN_CSTRING(strcpy(ascii, "-Infinity"));
- 
- 	ndig = DBL_DIG + extra_float_digits;
- 	if (ndig < 1)
- 		ndig = 1;
  
! 	sprintf(ascii, "%.*g", ndig, num);
  
  	PG_RETURN_CSTRING(ascii);
  }
--- 449,475 ----
  {
  	float8		num = PG_GETARG_FLOAT8(0);
  	char	   *ascii = (char *) palloc(MAXDOUBLEWIDTH + 1);
  
  	if (isnan(num))
  		PG_RETURN_CSTRING(strcpy(ascii, "NaN"));
  
! 	switch (is_infinite(num))
! 	{
! 		case 1:
! 			strcpy(ascii, "Infinity");
! 			break;
! 		case -1:
! 			strcpy(ascii, "-Infinity");
! 			break;
! 		default:
! 		{
! 			int ndig = DBL_DIG + extra_float_digits;
! 			if (ndig < 1)
! 				ndig = 1;
! 
! 			sprintf(ascii, "%.*g", ndig, num);
! 		}
! 	}
  
  	PG_RETURN_CSTRING(ascii);
  }
---------------------------(end of broadcast)---------------------------
TIP 7: don't forget to increase your free space map settings

Reply via email to