Re: [HACKERS] NaN support in NUMERIC data type

2009-04-09 Thread Sam Mason
On Wed, Apr 08, 2009 at 08:16:52PM -0400, Tom Lane wrote:
 Sam Mason s...@samason.me.uk writes:
  On Wed, Apr 08, 2009 at 06:11:59PM -0400, Tom Lane wrote:
  Anyway, I revised this a bit and applied to HEAD.
 
  I've not tested; but your changes look as though they will break:
SELECT 'Infinity'::float::numeric;
 
 That gives an error now, just as it did before, so I'm not sure what you
 think is broken about it ...

I shouldn't have responded last night; didn't realise how little of my
code was left so the semantics I was assuming weren't valid.


-- 
  Sam  http://samason.me.uk/

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] NaN support in NUMERIC data type

2009-04-08 Thread Sam Mason
On Tue, Apr 07, 2009 at 12:51:21PM -0400, Tom Lane wrote:
 Sam Mason s...@samason.me.uk writes:
SELECT 'NaN'::float8;
SELECT ' NaN'::float8;
SELECT 'NaN '::float8;
SELECT '+NaN'::float8;
SELECT '-NaN'::float8;
 
 Well, the +- part must be an artifact of your strtod() implementation;
 our own code isn't doing anything to accept that.  I think it's pretty
 bogus --- NaNs do not have signs.

OK, didn't actually check the code with that; no point worrying about it
then.

 IIRC, the explicit support for leading/trailing spaces is something that
 we added in float8in long after numeric_in was written, and I think just
 nobody thought about numeric at the time.  But it's clearly inconsistent
 to allow spaces around a regular value but not a NaN.

Good, I wanted to make sure it wasn't a deliberate thing before doing
too much.

 Possibly the logic for leading/trailing spaces could be pulled out
 of set_var_from_str and executed in numeric_in instead?

Yes, I didn't want to do this before because it's called from a
couple of other places.  I looked again and realised that we're
generating those in very fixed formats so don't need to worry about
leading/trailing spaces and hence can move the code up to numeric_in.

The attached patch gives set_var_from_str an endptr similar to strtod
so handling is closer to the float[48]in code.  I moved error reporting
code outside as well to cut down on the multiple identical calls.

The included patch was generated against 8.3.5 (because that's what I
had lying around when I started playing) but applies with a little fuzz
to the latest snapshot and does the right thing for me in both versions.

-- 
  Sam  http://samason.me.uk/
*** src/backend/utils/adt/numeric.c	2009-04-07 16:49:08.0 +0100
--- src/backend/utils/adt/numeric.c	2009-04-08 11:53:13.0 +0100
***
*** 238,244 
  static void free_var(NumericVar *var);
  static void zero_var(NumericVar *var);
  
! static void set_var_from_str(const char *str, NumericVar *dest);
  static void set_var_from_num(Numeric value, NumericVar *dest);
  static void set_var_from_var(NumericVar *value, NumericVar *dest);
  static char *get_str_from_var(NumericVar *var, int dscale);
--- 238,244 
  static void free_var(NumericVar *var);
  static void zero_var(NumericVar *var);
  
! static void set_var_from_str(const char *str, const char ** endptr, NumericVar *dest);
  static void set_var_from_num(Numeric value, NumericVar *dest);
  static void set_var_from_var(NumericVar *value, NumericVar *dest);
  static char *get_str_from_var(NumericVar *var, int dscale);
***
*** 310,315 
--- 310,317 
  numeric_in(PG_FUNCTION_ARGS)
  {
  	char	   *str = PG_GETARG_CSTRING(0);
+ 	char	   *orig_str;
+ 	const char *endptr;
  
  #ifdef NOT_USED
  	Oid			typelem = PG_GETARG_OID(1);
***
*** 318,335 
  	NumericVar	value;
  	Numeric		res;
  
! 	/*
! 	 * Check for NaN
  	 */
! 	if (pg_strcasecmp(str, NaN) == 0)
! 		PG_RETURN_NUMERIC(make_result(const_nan));
  
  	/*
  	 * Use set_var_from_str() to parse the input string and return it in the
  	 * packed DB storage format
  	 */
  	init_var(value);
! 	set_var_from_str(str, value);
  
  	apply_typmod(value, typmod);
  
--- 320,369 
  	NumericVar	value;
  	Numeric		res;
  
! 	/* 
! 	 * To allow us to generate sensible error messages we tuck the
! 	 * original start of the string away so we can use it later.
  	 */
! 	orig_str = str;
! 
! 	/* skip leading spaces */
! 	while (isspace((unsigned char) *str))
! 		str++;
  
  	/*
  	 * Use set_var_from_str() to parse the input string and return it in the
  	 * packed DB storage format
  	 */
  	init_var(value);
! 	set_var_from_str(str, endptr, value);
! 
! 	/*
! 	 * we didn't see anything that looked like a numeric value
! 	 */
! 	if (str == endptr) {
! 		/*
! 		 * Check for NaN
! 		 */
! 		if (pg_strncasecmp(str, NaN, 3) == 0) {
! 			value = const_nan;
! 			endptr = str + 3;
! 		} else
! 			ereport(ERROR,
! 	(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
! 	 errmsg(invalid input syntax for type numeric: \%s\,
! 			orig_str)));
! 	}
! 
! 	/* skip trailing spaces */
! 	while (isspace((unsigned char) *endptr))
! 		endptr++;
! 
! 	if (*endptr != '\0') {
! 		ereport(ERROR,
! (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
!  errmsg(invalid input syntax for type numeric: \%s\,
! 		orig_str)));
! 	}
  
  	apply_typmod(value, typmod);
  
***
*** 2056,2061 
--- 2090,2096 
  	Numeric		res;
  	NumericVar	result;
  	char		buf[DBL_DIG + 100];
+ 	const char *endptr;
  
  	if (isnan(val))
  		PG_RETURN_NUMERIC(make_result(const_nan));
***
*** 2064,2070 
  
  	init_var(result);
  
! 	set_var_from_str(buf, result);
  	res = make_result(result);
  
  	free_var(result);
--- 2099,2111 
  
  	init_var(result);
  
! 	set_var_from_str(buf, endptr, result);
! 	if (endptr == buf) {
! 		ereport(ERROR,
! 

Re: [HACKERS] NaN support in NUMERIC data type

2009-04-08 Thread Tom Lane
Sam Mason s...@samason.me.uk writes:
 On Tue, Apr 07, 2009 at 12:51:21PM -0400, Tom Lane wrote:
 IIRC, the explicit support for leading/trailing spaces is something that
 we added in float8in long after numeric_in was written, and I think just
 nobody thought about numeric at the time.  But it's clearly inconsistent
 to allow spaces around a regular value but not a NaN.

 The included patch was generated against 8.3.5 (because that's what I
 had lying around when I started playing) but applies with a little fuzz
 to the latest snapshot and does the right thing for me in both versions.

Hmm, did it do the right thing for NaN with a typmod?  I doubt
apply_typmod is safe for a NaN.  Anyway, I revised this a bit and
applied to HEAD.  I'm disinclined to back-patch; it's not really a bug
but a definition change, and we get flack when we put that sort of
change into stable branches ...

regards, tom lane

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] NaN support in NUMERIC data type

2009-04-08 Thread Sam Mason
On Wed, Apr 08, 2009 at 06:11:59PM -0400, Tom Lane wrote:
 Sam Mason s...@samason.me.uk writes:
  On Tue, Apr 07, 2009 at 12:51:21PM -0400, Tom Lane wrote:
  IIRC, the explicit support for leading/trailing spaces is something that
  we added in float8in long after numeric_in was written, and I think just
  nobody thought about numeric at the time.  But it's clearly inconsistent
  to allow spaces around a regular value but not a NaN.
 
  The included patch was generated against 8.3.5 (because that's what I
  had lying around when I started playing) but applies with a little fuzz
  to the latest snapshot and does the right thing for me in both versions.
 
 Hmm, did it do the right thing for NaN with a typmod?  I doubt
 apply_typmod is safe for a NaN.

Oops, good catch.  Didn't think to check for that.

 Anyway, I revised this a bit and applied to HEAD.

I've not tested; but your changes look as though they will break:

  SELECT 'Infinity'::float::numeric;

I think you'll get '0' back instead of an error; either that or it's too
late for me to be thinking straight!

 I'm disinclined to back-patch; it's not really a bug
 but a definition change, and we get flack when we put that sort of
 change into stable branches ...

OK


Out of personal interest; why did you translate:

  while(isspace(*p)) p++;

into more verbose forms?  Is it so it fits in with the style in rest of
the code, or does it actually do something different that I'm missing?

-- 
  Sam  http://samason.me.uk/

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] NaN support in NUMERIC data type

2009-04-08 Thread Tom Lane
Sam Mason s...@samason.me.uk writes:
 On Wed, Apr 08, 2009 at 06:11:59PM -0400, Tom Lane wrote:
 Anyway, I revised this a bit and applied to HEAD.

 I've not tested; but your changes look as though they will break:
   SELECT 'Infinity'::float::numeric;

That gives an error now, just as it did before, so I'm not sure what you
think is broken about it ...

 Out of personal interest; why did you translate:
   while(isspace(*p)) p++;
 into more verbose forms?

I just copied-and-pasted what was there before (inside the subroutine).
Didn't see much reason to change it.

regards, tom lane

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


[HACKERS] NaN support in NUMERIC data type

2009-04-07 Thread Sam Mason
Hi,

I've just noticed that the NUMERIC input function special cases NaN
values differently to the floating point input functions.  For example
the following are all accepted (on my system anyway):

  SELECT 'NaN'::float8;
  SELECT ' NaN'::float8;
  SELECT 'NaN '::float8;
  SELECT '+NaN'::float8;
  SELECT '-NaN'::float8;

whereas only the first is OK for numeric.  Is this deliberate?

A quick check of utils/adt/numeric.c would suggest that it's been
special cased as a optimisation so we don't allocate a numeric value
in set_var_from_str() unless we need to.

As a side note; I'm only really interested in the leading/trailing
spaces.  I only noticed the leading plus/minus sign when reading the
code and think it's probably better if a NaN is rejected if it has a
leading sign.  I think it would be better if it was consistent with
FLOAT, not sure how to do this in a platform independent way though.

I could submit a patch if you want; I'm unsure whether it's better to
duplicate code in numeric_in, do slightly more work and allocate memory
for NaN's when not strictly needed, or remove knowledge of NumericVar
from numeric_in altogether and push code into set_var_from_str.
Comments?

-- 
  Sam  http://samason.me.uk/

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] NaN support in NUMERIC data type

2009-04-07 Thread Tom Lane
Sam Mason s...@samason.me.uk writes:
 I've just noticed that the NUMERIC input function special cases NaN
 values differently to the floating point input functions.  For example
 the following are all accepted (on my system anyway):

   SELECT 'NaN'::float8;
   SELECT ' NaN'::float8;
   SELECT 'NaN '::float8;
   SELECT '+NaN'::float8;
   SELECT '-NaN'::float8;

 whereas only the first is OK for numeric.  Is this deliberate?

Well, the +- part must be an artifact of your strtod() implementation;
our own code isn't doing anything to accept that.  I think it's pretty
bogus --- NaNs do not have signs.

IIRC, the explicit support for leading/trailing spaces is something that
we added in float8in long after numeric_in was written, and I think just
nobody thought about numeric at the time.  But it's clearly inconsistent
to allow spaces around a regular value but not a NaN.

Possibly the logic for leading/trailing spaces could be pulled out
of set_var_from_str and executed in numeric_in instead?

regards, tom lane

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers