8
8
*
9
9
*
10
10
* 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 $
12
12
*
13
13
*-------------------------------------------------------------------------
14
14
*/
@@ -109,9 +109,30 @@ int extra_float_digits = 0; /* Added to DBL_DIG or FLT_DIG */
109
109
110
110
static void CheckFloat4Val (double val );
111
111
static void CheckFloat8Val (double val );
112
+ static int is_infinite (double val );
112
113
static int float4_cmp_internal (float4 a , float4 b );
113
114
static int float8_cmp_internal (float8 a , float8 b );
114
115
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
+ }
115
136
116
137
/*
117
138
* check to see if a float4 val is outside of the FLOAT4_MIN,
@@ -162,48 +183,78 @@ Datum
162
183
float4in (PG_FUNCTION_ARGS )
163
184
{
164
185
char * num = PG_GETARG_CSTRING (0 );
186
+ char * orig_num ;
165
187
double val ;
166
188
char * endptr ;
167
189
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
+
168
221
errno = 0 ;
169
222
val = strtod (num , & endptr );
170
223
171
224
if (errno == ERANGE )
172
225
ereport (ERROR ,
173
226
(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 )));
175
229
230
+ /* did we not see anything that looks like a double? */
176
231
if (num == endptr )
177
232
{
178
233
/*
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.
186
237
*/
187
- if (* num == '\0' )
238
+ if (strncasecmp ( num , "NaN" , 3 ) == 0 )
188
239
{
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 )
197
240
val = NAN ;
198
- else if (strcasecmp (num , "Infinity" ) == 0 )
241
+ endptr = num + 3 ;
242
+ }
243
+ else if (strncasecmp (num , "Infinity" , 8 ) == 0 )
244
+ {
199
245
val = HUGE_VAL ;
200
- else if (strcasecmp (num , "-Infinity" ) == 0 )
246
+ endptr = num + 8 ;
247
+ }
248
+ else if (strncasecmp (num , "-Infinity" , 9 ) == 0 )
249
+ {
201
250
val = - HUGE_VAL ;
251
+ endptr = num + 9 ;
252
+ }
202
253
else
203
254
ereport (ERROR ,
204
255
(errcode (ERRCODE_INVALID_TEXT_REPRESENTATION ),
205
256
errmsg ("invalid input syntax for type real: \"%s\"" ,
206
- num )));
257
+ orig_num )));
207
258
}
208
259
209
260
/* skip trailing whitespace */
@@ -215,11 +266,11 @@ float4in(PG_FUNCTION_ARGS)
215
266
ereport (ERROR ,
216
267
(errcode (ERRCODE_INVALID_TEXT_REPRESENTATION ),
217
268
errmsg ("invalid input syntax for type real: \"%s\"" ,
218
- num )));
269
+ orig_num )));
219
270
220
271
/*
221
272
* if we get here, we have a legal double, still need to check to see
222
- * if it's a legal float
273
+ * if it's a legal float4
223
274
*/
224
275
if (!isinf (val ))
225
276
CheckFloat4Val (val );
@@ -236,22 +287,27 @@ float4out(PG_FUNCTION_ARGS)
236
287
{
237
288
float4 num = PG_GETARG_FLOAT4 (0 );
238
289
char * ascii = (char * ) palloc (MAXFLOATWIDTH + 1 );
239
- int infflag ;
240
- int ndig ;
241
290
242
291
if (isnan (num ))
243
292
PG_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" ));
249
293
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 ;
253
307
254
- sprintf (ascii , "%.*g" , ndig , num );
308
+ sprintf (ascii , "%.*g" , ndig , num );
309
+ }
310
+ }
255
311
256
312
PG_RETURN_CSTRING (ascii );
257
313
}
@@ -292,48 +348,78 @@ Datum
292
348
float8in (PG_FUNCTION_ARGS )
293
349
{
294
350
char * num = PG_GETARG_CSTRING (0 );
351
+ char * orig_num ;
295
352
double val ;
296
353
char * endptr ;
297
354
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
+
298
386
errno = 0 ;
299
387
val = strtod (num , & endptr );
300
388
301
389
if (errno == ERANGE )
302
390
ereport (ERROR ,
303
391
(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 )));
305
394
395
+ /* did we not see anything that looks like a double? */
306
396
if (num == endptr )
307
397
{
308
398
/*
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.
316
402
*/
317
- if (* num == '\0' )
403
+ if (strncasecmp ( num , "NaN" , 3 ) == 0 )
318
404
{
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 )
327
405
val = NAN ;
328
- else if (strcasecmp (num , "Infinity" ) == 0 )
406
+ endptr = num + 3 ;
407
+ }
408
+ else if (strncasecmp (num , "Infinity" , 8 ) == 0 )
409
+ {
329
410
val = HUGE_VAL ;
330
- else if (strcasecmp (num , "-Infinity" ) == 0 )
411
+ endptr = num + 8 ;
412
+ }
413
+ else if (strncasecmp (num , "-Infinity" , 9 ) == 0 )
414
+ {
331
415
val = - HUGE_VAL ;
416
+ endptr = num + 9 ;
417
+ }
332
418
else
333
419
ereport (ERROR ,
334
420
(errcode (ERRCODE_INVALID_TEXT_REPRESENTATION ),
335
421
errmsg ("invalid input syntax for type double precision: \"%s\"" ,
336
- num )));
422
+ orig_num )));
337
423
}
338
424
339
425
/* skip trailing whitespace */
@@ -345,7 +431,7 @@ float8in(PG_FUNCTION_ARGS)
345
431
ereport (ERROR ,
346
432
(errcode (ERRCODE_INVALID_TEXT_REPRESENTATION ),
347
433
errmsg ("invalid input syntax for type double precision: \"%s\"" ,
348
- num )));
434
+ orig_num )));
349
435
350
436
if (!isinf (val ))
351
437
CheckFloat8Val (val );
@@ -362,22 +448,27 @@ float8out(PG_FUNCTION_ARGS)
362
448
{
363
449
float8 num = PG_GETARG_FLOAT8 (0 );
364
450
char * ascii = (char * ) palloc (MAXDOUBLEWIDTH + 1 );
365
- int infflag ;
366
- int ndig ;
367
451
368
452
if (isnan (num ))
369
453
PG_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" ));
375
454
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 ;
379
468
380
- sprintf (ascii , "%.*g" , ndig , num );
469
+ sprintf (ascii , "%.*g" , ndig , num );
470
+ }
471
+ }
381
472
382
473
PG_RETURN_CSTRING (ascii );
383
474
}
0 commit comments