8
8
*
9
9
*
10
10
* IDENTIFICATION
11
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.37 2000/01/26 05:56:42 momjian Exp $
11
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.38 2000/02/24 01:59:17 tgl Exp $
12
12
*
13
13
*-------------------------------------------------------------------------
14
14
*/
15
15
#include <ctype.h>
16
+ #include <errno.h>
17
+ #include <float.h>
16
18
17
19
#include "postgres.h"
20
+
18
21
#include "access/heapam.h"
19
22
#include "catalog/pg_operator.h"
20
23
#include "catalog/pg_type.h"
32
35
#include "utils/syscache.h"
33
36
34
37
static void disallow_setop (char * op , Type optype , Node * operand );
38
+ static bool fitsInFloat (Value * value );
39
+
35
40
36
41
/* make_parsestate()
37
42
* Allocate and initialize a new ParseState.
@@ -393,11 +398,25 @@ transformArraySubscripts(ParseState *pstate,
393
398
* make_const
394
399
*
395
400
* Convert a Value node (as returned by the grammar) to a Const node
396
- * of the "natural" type for the constant. For strings we produce
397
- * a constant of type UNKNOWN ---- representation is the same as text,
398
- * but this indicates to later type resolution that we're not sure that
399
- * it should be considered text. Explicit "NULL" constants are also
400
- * typed as UNKNOWN.
401
+ * of the "natural" type for the constant. Note that this routine is
402
+ * only used when there is no explicit cast for the constant, so we
403
+ * have to guess what type is wanted.
404
+ *
405
+ * For string literals we produce a constant of type UNKNOWN ---- whose
406
+ * representation is the same as text, but it indicates to later type
407
+ * resolution that we're not sure that it should be considered text.
408
+ * Explicit "NULL" constants are also typed as UNKNOWN.
409
+ *
410
+ * For integers and floats we produce int4, float8, or numeric depending
411
+ * on the value of the number. XXX In some cases it would be nice to take
412
+ * context into account when determining the type to convert to, but in
413
+ * other cases we can't delay the type choice. One possibility is to invent
414
+ * a dummy type "UNKNOWNNUMERIC" that's treated similarly to UNKNOWN;
415
+ * that would allow us to do the right thing in examples like a simple
416
+ * INSERT INTO table (numericcolumn) VALUES (1.234), since we wouldn't
417
+ * have to resolve the unknown type until we knew the destination column
418
+ * type. On the other hand UNKNOWN has considerable problems of its own.
419
+ * We would not like "SELECT 1.2 + 3.4" to claim it can't choose a type.
401
420
*/
402
421
Const *
403
422
make_const (Value * value )
@@ -419,18 +438,25 @@ make_const(Value *value)
419
438
break ;
420
439
421
440
case T_Float :
441
+ if (fitsInFloat (value ))
422
442
{
423
- float64 dummy ;
443
+ float64 fltval = ( float64 ) palloc ( sizeof ( float64data )) ;
424
444
425
- dummy = (float64 ) palloc (sizeof (float64data ));
426
- * dummy = floatVal (value );
427
-
428
- val = Float64GetDatum (dummy );
445
+ * fltval = floatVal (value );
446
+ val = Float64GetDatum (fltval );
429
447
430
448
typeid = FLOAT8OID ;
431
449
typelen = sizeof (float64data );
432
450
typebyval = false;
433
451
}
452
+ else
453
+ {
454
+ val = PointerGetDatum (numeric_in (strVal (value ), 0 , -1 ));
455
+
456
+ typeid = NUMERICOID ;
457
+ typelen = -1 ; /* variable len */
458
+ typebyval = false;
459
+ }
434
460
break ;
435
461
436
462
case T_String :
@@ -441,11 +467,11 @@ make_const(Value *value)
441
467
typebyval = false;
442
468
break ;
443
469
444
- case T_Null :
445
470
default :
446
- if ( nodeTag (value ) != T_Null )
447
- elog ( NOTICE , "make_const: unknown type %d\n" , nodeTag ( value ));
471
+ elog ( NOTICE , "make_const: unknown type %d" , nodeTag (value ));
472
+ /* FALLTHROUGH */
448
473
474
+ case T_Null :
449
475
/* return a null const */
450
476
con = makeConst (UNKNOWNOID ,
451
477
-1 ,
@@ -467,3 +493,45 @@ make_const(Value *value)
467
493
468
494
return con ;
469
495
}
496
+
497
+ /*
498
+ * Decide whether a T_Float value fits in float8, or must be treated as
499
+ * type "numeric". We check the number of digits and check for overflow/
500
+ * underflow. (With standard compilation options, Postgres' NUMERIC type
501
+ * can handle decimal exponents up to 1000, considerably more than most
502
+ * implementations of float8, so this is a sensible test.)
503
+ */
504
+ static bool
505
+ fitsInFloat (Value * value )
506
+ {
507
+ const char * ptr ;
508
+ int ndigits ;
509
+ char * endptr ;
510
+
511
+ /*
512
+ * Count digits, ignoring leading zeroes (but not trailing zeroes).
513
+ * DBL_DIG is the maximum safe number of digits for "double".
514
+ */
515
+ ptr = strVal (value );
516
+ while (* ptr == '+' || * ptr == '-' || * ptr == '0' || * ptr == '.' )
517
+ ptr ++ ;
518
+ ndigits = 0 ;
519
+ for (; * ptr ; ptr ++ )
520
+ {
521
+ if (isdigit (* ptr ))
522
+ ndigits ++ ;
523
+ else if (* ptr == 'e' || * ptr == 'E' )
524
+ break ; /* don't count digits in exponent */
525
+ }
526
+ if (ndigits > DBL_DIG )
527
+ return false;
528
+ /*
529
+ * Use strtod() to check for overflow/underflow.
530
+ */
531
+ errno = 0 ;
532
+ (void ) strtod (strVal (value ), & endptr );
533
+ if (* endptr != '\0' || errno != 0 )
534
+ return false;
535
+
536
+ return true;
537
+ }
0 commit comments