88 *
99 *
1010 * IDENTIFICATION
11- * $PostgreSQL: pgsql/src/backend/utils/adt/float.c,v 1.99 2004/03/12 00:25:40 neilc Exp $
11+ * $PostgreSQL: pgsql/src/backend/utils/adt/float.c,v 1.100 2004/03/14 05:22:52 neilc Exp $
1212 *
1313 *-------------------------------------------------------------------------
1414 */
@@ -109,9 +109,30 @@ intextra_float_digits = 0;/* Added to DBL_DIG or FLT_DIG */
109109
110110static void CheckFloat4Val (double val );
111111static void CheckFloat8Val (double val );
112+ static int is_infinite (double val );
112113static int float4_cmp_internal (float4 a ,float4 b );
113114static int float8_cmp_internal (float8 a ,float8 b );
114115
116+ /*
117+ * Returns -1 if 'val' represents negative infinity, 1 if 'val'
118+ * represents (positive) infinity, and 0 otherwise. On some platforms,
119+ * this is equivalent to the isinf() macro, but not everywhere: C99
120+ * does not specify that isinf() needs to distinguish between positive
121+ * and negative infinity.
122+ */
123+ static int
124+ is_infinite (double val )
125+ {
126+ int inf = isinf (val );
127+
128+ if (inf == 0 )
129+ return 0 ;
130+
131+ if (val > 0 )
132+ return 1 ;
133+
134+ return -1 ;
135+ }
115136
116137/*
117138 * check to see if a float4 val is outside of the FLOAT4_MIN,
@@ -162,48 +183,78 @@ Datum
162183float4in (PG_FUNCTION_ARGS )
163184{
164185char * num = PG_GETARG_CSTRING (0 );
186+ char * orig_num ;
165187double val ;
166188char * endptr ;
167189
190+ /*
191+ * endptr points to the first character _after_ the sequence we
192+ * recognized as a valid floating point number. orig_num points to
193+ * the original input string.
194+ */
195+ orig_num = num ;
196+
197+ /*
198+ * Check for an empty-string input to begin with, to avoid
199+ * the vagaries of strtod() on different platforms.
200+ *
201+ * In releases prior to 7.5, we accepted an empty string as valid
202+ * input (yielding a float4 of 0). In 7.5, we accept empty
203+ * strings, but emit a warning noting that the feature is
204+ * deprecated. In 7.6+, the warning should be replaced by an
205+ * error.
206+ */
207+ if (* num == '\0' )
208+ {
209+ ereport (WARNING ,
210+ (errcode (ERRCODE_WARNING_DEPRECATED_FEATURE ),
211+ errmsg ("deprecated input syntax for type real: \"\"" ),
212+ errdetail ("This input will be rejected in "
213+ "a future release of PostgreSQL." )));
214+ PG_RETURN_FLOAT4 ((float4 )0.0 );
215+ }
216+
217+ /* skip leading whitespace */
218+ while (* num != '\0' && isspace (* num ))
219+ num ++ ;
220+
168221errno = 0 ;
169222val = strtod (num ,& endptr );
170223
171224if (errno == ERANGE )
172225ereport (ERROR ,
173226(errcode (ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE ),
174- errmsg ("\"%s\" is out of range for type real" ,num )));
227+ errmsg ("\"%s\" is out of range for type real" ,
228+ orig_num )));
175229
230+ /* did we not see anything that looks like a double? */
176231if (num == endptr )
177232{
178233/*
179- * We didn't find anything that looks like a float in the input
180- *
181- * In releases prior to 7.5, we accepted an empty string as
182- * valid input (yielding a float8 of 0). In 7.5, we accept
183- * empty strings, but emit a warning noting that the feature
184- * is deprecated. In 7.6+, the warning should be replaced by
185- * an error.
234+ * C99 requires that strtod() accept NaN and [-]Infinity, but
235+ * not all platforms support that yet. Therefore, we check for
236+ * these inputs ourselves.
186237 */
187- if (* num == '\0' )
238+ if (strncasecmp ( num , "NaN" , 3 ) == 0 )
188239{
189- ereport (WARNING ,
190- (errcode (ERRCODE_WARNING_DEPRECATED_FEATURE ),
191- errmsg ("deprecated input syntax for type real: \"\"" ),
192- errdetail ("This input will be rejected in "
193- "a future release of PostgreSQL." )));
194- Assert (val == 0.0 );
195- }
196- else if (strcasecmp (num ,"NaN" )== 0 )
197240val = NAN ;
198- else if (strcasecmp (num ,"Infinity" )== 0 )
241+ endptr = num + 3 ;
242+ }
243+ else if (strncasecmp (num ,"Infinity" ,8 )== 0 )
244+ {
199245val = HUGE_VAL ;
200- else if (strcasecmp (num ,"-Infinity" )== 0 )
246+ endptr = num + 8 ;
247+ }
248+ else if (strncasecmp (num ,"-Infinity" ,9 )== 0 )
249+ {
201250val = - HUGE_VAL ;
251+ endptr = num + 9 ;
252+ }
202253else
203254ereport (ERROR ,
204255(errcode (ERRCODE_INVALID_TEXT_REPRESENTATION ),
205256errmsg ("invalid input syntax for type real: \"%s\"" ,
206- num )));
257+ orig_num )));
207258}
208259
209260/* skip trailing whitespace */
@@ -215,11 +266,11 @@ float4in(PG_FUNCTION_ARGS)
215266ereport (ERROR ,
216267(errcode (ERRCODE_INVALID_TEXT_REPRESENTATION ),
217268errmsg ("invalid input syntax for type real: \"%s\"" ,
218- num )));
269+ orig_num )));
219270
220271/*
221272 * if we get here, we have a legal double, still need to check to see
222- * if it's a legalfloat
273+ * if it's a legalfloat4
223274 */
224275if (!isinf (val ))
225276CheckFloat4Val (val );
@@ -236,22 +287,27 @@ float4out(PG_FUNCTION_ARGS)
236287{
237288float4 num = PG_GETARG_FLOAT4 (0 );
238289char * ascii = (char * )palloc (MAXFLOATWIDTH + 1 );
239- int infflag ;
240- int ndig ;
241290
242291if (isnan (num ))
243292PG_RETURN_CSTRING (strcpy (ascii ,"NaN" ));
244- infflag = isinf (num );
245- if (infflag > 0 )
246- PG_RETURN_CSTRING (strcpy (ascii ,"Infinity" ));
247- if (infflag < 0 )
248- PG_RETURN_CSTRING (strcpy (ascii ,"-Infinity" ));
249293
250- ndig = FLT_DIG + extra_float_digits ;
251- if (ndig < 1 )
252- ndig = 1 ;
294+ switch (is_infinite (num ))
295+ {
296+ case 1 :
297+ strcpy (ascii ,"Infinity" );
298+ break ;
299+ case -1 :
300+ strcpy (ascii ,"-Infinity" );
301+ break ;
302+ default :
303+ {
304+ int ndig = FLT_DIG + extra_float_digits ;
305+ if (ndig < 1 )
306+ ndig = 1 ;
253307
254- sprintf (ascii ,"%.*g" ,ndig ,num );
308+ sprintf (ascii ,"%.*g" ,ndig ,num );
309+ }
310+ }
255311
256312PG_RETURN_CSTRING (ascii );
257313}
@@ -292,48 +348,78 @@ Datum
292348float8in (PG_FUNCTION_ARGS )
293349{
294350char * num = PG_GETARG_CSTRING (0 );
351+ char * orig_num ;
295352double val ;
296353char * endptr ;
297354
355+ /*
356+ * endptr points to the first character _after_ the sequence we
357+ * recognized as a valid floating point number. orig_num points to
358+ * the original input string.
359+ */
360+ orig_num = num ;
361+
362+ /*
363+ * Check for an empty-string input to begin with, to avoid
364+ * the vagaries of strtod() on different platforms.
365+ *
366+ * In releases prior to 7.5, we accepted an empty string as valid
367+ * input (yielding a float8 of 0). In 7.5, we accept empty
368+ * strings, but emit a warning noting that the feature is
369+ * deprecated. In 7.6+, the warning should be replaced by an
370+ * error.
371+ */
372+ if (* num == '\0' )
373+ {
374+ ereport (WARNING ,
375+ (errcode (ERRCODE_WARNING_DEPRECATED_FEATURE ),
376+ errmsg ("deprecated input syntax for type double precision: \"\"" ),
377+ errdetail ("This input will be rejected in "
378+ "a future release of PostgreSQL." )));
379+ PG_RETURN_FLOAT8 (0.0 );
380+ }
381+
382+ /* skip leading whitespace */
383+ while (* num != '\0' && isspace (* num ))
384+ num ++ ;
385+
298386errno = 0 ;
299387val = strtod (num ,& endptr );
300388
301389if (errno == ERANGE )
302390ereport (ERROR ,
303391(errcode (ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE ),
304- errmsg ("\"%s\" is out of range for type double precision" ,num )));
392+ errmsg ("\"%s\" is out of range for type double precision" ,
393+ orig_num )));
305394
395+ /* did we not see anything that looks like a double? */
306396if (num == endptr )
307397{
308398/*
309- * We didn't find anything that looks like a float in the input
310- *
311- * In releases prior to 7.5, we accepted an empty string as
312- * valid input (yielding a float8 of 0). In 7.5, we accept
313- * empty strings, but emit a warning noting that the feature
314- * is deprecated. In 7.6+, the warning should be replaced by
315- * an error.
399+ * C99 requires that strtod() accept NaN and [-]Infinity, but
400+ * not all platforms support that yet. Therefore, we check for
401+ * these inputs ourselves.
316402 */
317- if (* num == '\0' )
403+ if (strncasecmp ( num , "NaN" , 3 ) == 0 )
318404{
319- ereport (WARNING ,
320- (errcode (ERRCODE_WARNING_DEPRECATED_FEATURE ),
321- errmsg ("deprecated input syntax for type double precision: \"\"" ),
322- errdetail ("This input will be rejected in "
323- "a future release of PostgreSQL." )));
324- Assert (val == 0.0 );
325- }
326- else if (strcasecmp (num ,"NaN" )== 0 )
327405val = NAN ;
328- else if (strcasecmp (num ,"Infinity" )== 0 )
406+ endptr = num + 3 ;
407+ }
408+ else if (strncasecmp (num ,"Infinity" ,8 )== 0 )
409+ {
329410val = HUGE_VAL ;
330- else if (strcasecmp (num ,"-Infinity" )== 0 )
411+ endptr = num + 8 ;
412+ }
413+ else if (strncasecmp (num ,"-Infinity" ,9 )== 0 )
414+ {
331415val = - HUGE_VAL ;
416+ endptr = num + 9 ;
417+ }
332418else
333419ereport (ERROR ,
334420(errcode (ERRCODE_INVALID_TEXT_REPRESENTATION ),
335421errmsg ("invalid input syntax for type double precision: \"%s\"" ,
336- num )));
422+ orig_num )));
337423}
338424
339425/* skip trailing whitespace */
@@ -345,7 +431,7 @@ float8in(PG_FUNCTION_ARGS)
345431ereport (ERROR ,
346432(errcode (ERRCODE_INVALID_TEXT_REPRESENTATION ),
347433errmsg ("invalid input syntax for type double precision: \"%s\"" ,
348- num )));
434+ orig_num )));
349435
350436if (!isinf (val ))
351437CheckFloat8Val (val );
@@ -362,22 +448,27 @@ float8out(PG_FUNCTION_ARGS)
362448{
363449float8 num = PG_GETARG_FLOAT8 (0 );
364450char * ascii = (char * )palloc (MAXDOUBLEWIDTH + 1 );
365- int infflag ;
366- int ndig ;
367451
368452if (isnan (num ))
369453PG_RETURN_CSTRING (strcpy (ascii ,"NaN" ));
370- infflag = isinf (num );
371- if (infflag > 0 )
372- PG_RETURN_CSTRING (strcpy (ascii ,"Infinity" ));
373- if (infflag < 0 )
374- PG_RETURN_CSTRING (strcpy (ascii ,"-Infinity" ));
375454
376- ndig = DBL_DIG + extra_float_digits ;
377- if (ndig < 1 )
378- ndig = 1 ;
455+ switch (is_infinite (num ))
456+ {
457+ case 1 :
458+ strcpy (ascii ,"Infinity" );
459+ break ;
460+ case -1 :
461+ strcpy (ascii ,"-Infinity" );
462+ break ;
463+ default :
464+ {
465+ int ndig = DBL_DIG + extra_float_digits ;
466+ if (ndig < 1 )
467+ ndig = 1 ;
379468
380- sprintf (ascii ,"%.*g" ,ndig ,num );
469+ sprintf (ascii ,"%.*g" ,ndig ,num );
470+ }
471+ }
381472
382473PG_RETURN_CSTRING (ascii );
383474}