mirror of
https://github.com/postgres/postgres.git
synced 2025-06-05 23:56:58 +03:00
Make make_const() check the size and precision of a T_Float Value,
and produce either FLOAT8 or NUMERIC output depending on whether the value fits in a float8 or not. This is almost back to the way the code was before I changed T_Float, but there is a critical difference: now, when a numeric constant doesn't fit in float8, it will be treated as type NUMERIC instead of type UNKNOWN.
This commit is contained in:
parent
399a570fe2
commit
512669db9e
@ -11,7 +11,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.149 2000/02/22 00:05:04 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.150 2000/02/24 01:59:17 tgl Exp $
|
||||||
*
|
*
|
||||||
* HISTORY
|
* HISTORY
|
||||||
* AUTHOR DATE MAJOR EVENT
|
* AUTHOR DATE MAJOR EVENT
|
||||||
@ -5606,14 +5606,17 @@ Oid param_type(int t)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The optimizer doesn't like '-' 4 for index use. It only checks for
|
* doNegate --- handle negation of a numeric constant.
|
||||||
* Var '=' Const. It wants an integer of -4, so we try to merge the
|
|
||||||
* minus into the constant.
|
|
||||||
*
|
*
|
||||||
* This code is no longer essential as of 10/1999, since the optimizer
|
* Formerly, we did this here because the optimizer couldn't cope with
|
||||||
* now has a constant-subexpression simplifier. However, we can save
|
* indexquals that looked like "var = -4" --- it wants "var = const"
|
||||||
* a few cycles throughout the parse and rewrite stages if we collapse
|
* and a unary minus operator applied to a constant didn't qualify.
|
||||||
* the minus into the constant sooner rather than later...
|
* As of Postgres 7.0, that problem doesn't exist anymore because there
|
||||||
|
* is a constant-subexpression simplifier in the optimizer. However,
|
||||||
|
* there's still a good reason for doing this here, which is that we can
|
||||||
|
* postpone committing to a particular internal representation for simple
|
||||||
|
* negative constants. It's better to leave "-123.456" in string form
|
||||||
|
* until we know what the desired type is.
|
||||||
*/
|
*/
|
||||||
static Node *
|
static Node *
|
||||||
doNegate(Node *n)
|
doNegate(Node *n)
|
||||||
|
@ -8,13 +8,16 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.37 2000/01/26 05:56:42 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.38 2000/02/24 01:59:17 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <float.h>
|
||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
#include "access/heapam.h"
|
#include "access/heapam.h"
|
||||||
#include "catalog/pg_operator.h"
|
#include "catalog/pg_operator.h"
|
||||||
#include "catalog/pg_type.h"
|
#include "catalog/pg_type.h"
|
||||||
@ -32,6 +35,8 @@
|
|||||||
#include "utils/syscache.h"
|
#include "utils/syscache.h"
|
||||||
|
|
||||||
static void disallow_setop(char *op, Type optype, Node *operand);
|
static void disallow_setop(char *op, Type optype, Node *operand);
|
||||||
|
static bool fitsInFloat(Value *value);
|
||||||
|
|
||||||
|
|
||||||
/* make_parsestate()
|
/* make_parsestate()
|
||||||
* Allocate and initialize a new ParseState.
|
* Allocate and initialize a new ParseState.
|
||||||
@ -393,11 +398,25 @@ transformArraySubscripts(ParseState *pstate,
|
|||||||
* make_const
|
* make_const
|
||||||
*
|
*
|
||||||
* Convert a Value node (as returned by the grammar) to a Const node
|
* Convert a Value node (as returned by the grammar) to a Const node
|
||||||
* of the "natural" type for the constant. For strings we produce
|
* of the "natural" type for the constant. Note that this routine is
|
||||||
* a constant of type UNKNOWN ---- representation is the same as text,
|
* only used when there is no explicit cast for the constant, so we
|
||||||
* but this indicates to later type resolution that we're not sure that
|
* have to guess what type is wanted.
|
||||||
* it should be considered text. Explicit "NULL" constants are also
|
*
|
||||||
* typed as UNKNOWN.
|
* For string literals we produce a constant of type UNKNOWN ---- whose
|
||||||
|
* representation is the same as text, but it indicates to later type
|
||||||
|
* resolution that we're not sure that it should be considered text.
|
||||||
|
* Explicit "NULL" constants are also typed as UNKNOWN.
|
||||||
|
*
|
||||||
|
* For integers and floats we produce int4, float8, or numeric depending
|
||||||
|
* on the value of the number. XXX In some cases it would be nice to take
|
||||||
|
* context into account when determining the type to convert to, but in
|
||||||
|
* other cases we can't delay the type choice. One possibility is to invent
|
||||||
|
* a dummy type "UNKNOWNNUMERIC" that's treated similarly to UNKNOWN;
|
||||||
|
* that would allow us to do the right thing in examples like a simple
|
||||||
|
* INSERT INTO table (numericcolumn) VALUES (1.234), since we wouldn't
|
||||||
|
* have to resolve the unknown type until we knew the destination column
|
||||||
|
* type. On the other hand UNKNOWN has considerable problems of its own.
|
||||||
|
* We would not like "SELECT 1.2 + 3.4" to claim it can't choose a type.
|
||||||
*/
|
*/
|
||||||
Const *
|
Const *
|
||||||
make_const(Value *value)
|
make_const(Value *value)
|
||||||
@ -419,18 +438,25 @@ make_const(Value *value)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case T_Float:
|
case T_Float:
|
||||||
|
if (fitsInFloat(value))
|
||||||
{
|
{
|
||||||
float64 dummy;
|
float64 fltval = (float64) palloc(sizeof(float64data));
|
||||||
|
|
||||||
dummy = (float64) palloc(sizeof(float64data));
|
*fltval = floatVal(value);
|
||||||
*dummy = floatVal(value);
|
val = Float64GetDatum(fltval);
|
||||||
|
|
||||||
val = Float64GetDatum(dummy);
|
|
||||||
|
|
||||||
typeid = FLOAT8OID;
|
typeid = FLOAT8OID;
|
||||||
typelen = sizeof(float64data);
|
typelen = sizeof(float64data);
|
||||||
typebyval = false;
|
typebyval = false;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
val = PointerGetDatum(numeric_in(strVal(value), 0, -1));
|
||||||
|
|
||||||
|
typeid = NUMERICOID;
|
||||||
|
typelen = -1; /* variable len */
|
||||||
|
typebyval = false;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_String:
|
case T_String:
|
||||||
@ -441,11 +467,11 @@ make_const(Value *value)
|
|||||||
typebyval = false;
|
typebyval = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_Null:
|
|
||||||
default:
|
default:
|
||||||
if (nodeTag(value) != T_Null)
|
elog(NOTICE, "make_const: unknown type %d", nodeTag(value));
|
||||||
elog(NOTICE, "make_const: unknown type %d\n", nodeTag(value));
|
/* FALLTHROUGH */
|
||||||
|
|
||||||
|
case T_Null:
|
||||||
/* return a null const */
|
/* return a null const */
|
||||||
con = makeConst(UNKNOWNOID,
|
con = makeConst(UNKNOWNOID,
|
||||||
-1,
|
-1,
|
||||||
@ -467,3 +493,45 @@ make_const(Value *value)
|
|||||||
|
|
||||||
return con;
|
return con;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Decide whether a T_Float value fits in float8, or must be treated as
|
||||||
|
* type "numeric". We check the number of digits and check for overflow/
|
||||||
|
* underflow. (With standard compilation options, Postgres' NUMERIC type
|
||||||
|
* can handle decimal exponents up to 1000, considerably more than most
|
||||||
|
* implementations of float8, so this is a sensible test.)
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
fitsInFloat(Value *value)
|
||||||
|
{
|
||||||
|
const char *ptr;
|
||||||
|
int ndigits;
|
||||||
|
char *endptr;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Count digits, ignoring leading zeroes (but not trailing zeroes).
|
||||||
|
* DBL_DIG is the maximum safe number of digits for "double".
|
||||||
|
*/
|
||||||
|
ptr = strVal(value);
|
||||||
|
while (*ptr == '+' || *ptr == '-' || *ptr == '0' || *ptr == '.')
|
||||||
|
ptr++;
|
||||||
|
ndigits = 0;
|
||||||
|
for (; *ptr; ptr++)
|
||||||
|
{
|
||||||
|
if (isdigit(*ptr))
|
||||||
|
ndigits++;
|
||||||
|
else if (*ptr == 'e' || *ptr == 'E')
|
||||||
|
break; /* don't count digits in exponent */
|
||||||
|
}
|
||||||
|
if (ndigits > DBL_DIG)
|
||||||
|
return false;
|
||||||
|
/*
|
||||||
|
* Use strtod() to check for overflow/underflow.
|
||||||
|
*/
|
||||||
|
errno = 0;
|
||||||
|
(void) strtod(strVal(value), &endptr);
|
||||||
|
if (*endptr != '\0' || errno != 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user