diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2002-09-18 21:35:25 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2002-09-18 21:35:25 +0000 |
commit | b26dfb95222fddd25322bdddf3a5a58d3392d8b1 (patch) | |
tree | 757cf0bafab985d38a5c84d3afebe5edd34c4f27 /src/backend/parser/parse_node.c | |
parent | cc70ba2e4daa78ba99619770e19beb06de3dfd1c (diff) | |
download | postgresql-b26dfb95222fddd25322bdddf3a5a58d3392d8b1.tar.gz postgresql-b26dfb95222fddd25322bdddf3a5a58d3392d8b1.zip |
Extend pg_cast castimplicit column to a three-way value; this allows us
to be flexible about assignment casts without introducing ambiguity in
operator/function resolution. Introduce a well-defined promotion hierarchy
for numeric datatypes (int2->int4->int8->numeric->float4->float8).
Change make_const to initially label numeric literals as int4, int8, or
numeric (never float8 anymore).
Explicitly mark Func and RelabelType nodes to indicate whether they came
from a function call, explicit cast, or implicit cast; use this to do
reverse-listing more accurately and without so many heuristics.
Explicit casts to char, varchar, bit, varbit will truncate or pad without
raising an error (the pre-7.2 behavior), while assigning to a column without
any explicit cast will still raise an error for wrong-length data like 7.3.
This more nearly follows the SQL spec than 7.2 behavior (we should be
reporting a 'completion condition' in the explicit-cast cases, but we have
no mechanism for that, so just do silent truncation).
Fix some problems with enforcement of typmod for array elements;
it didn't work at all in 'UPDATE ... SET array[n] = foo', for example.
Provide a generalized array_length_coerce() function to replace the
specialized per-array-type functions that used to be needed (and were
missing for NUMERIC as well as all the datetime types).
Add missing conversions int8<->float4, text<->numeric, oid<->int8.
initdb forced.
Diffstat (limited to 'src/backend/parser/parse_node.c')
-rw-r--r-- | src/backend/parser/parse_node.c | 126 |
1 files changed, 37 insertions, 89 deletions
diff --git a/src/backend/parser/parse_node.c b/src/backend/parser/parse_node.c index 391694fa198..408fb4f11f6 100644 --- a/src/backend/parser/parse_node.c +++ b/src/backend/parser/parse_node.c @@ -1,27 +1,22 @@ /*------------------------------------------------------------------------- * * parse_node.c - * various routines that make nodes for query plans + * various routines that make nodes for querytrees * * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.68 2002/09/04 20:31:24 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.69 2002/09/18 21:35:22 tgl Exp $ * *------------------------------------------------------------------------- */ #include "postgres.h" -#include <ctype.h> -#include <errno.h> -#include <float.h> - #include "access/heapam.h" #include "catalog/pg_operator.h" #include "catalog/pg_type.h" -#include "fmgr.h" #include "nodes/makefuncs.h" #include "parser/parsetree.h" #include "parser/parse_coerce.h" @@ -29,14 +24,11 @@ #include "parser/parse_node.h" #include "parser/parse_oper.h" #include "parser/parse_relation.h" -#include "parser/parse_target.h" -#include "parser/parse_type.h" #include "utils/builtins.h" -#include "utils/varbit.h" +#include "utils/int8.h" #include "utils/lsyscache.h" #include "utils/syscache.h" - -static bool fitsInFloat(Value *value); +#include "utils/varbit.h" /* make_parsestate() @@ -70,8 +62,8 @@ make_operand(Node *tree, Oid orig_typeId, Oid target_typeId) { /* must coerce? */ if (target_typeId != orig_typeId) - result = coerce_type(NULL, tree, orig_typeId, target_typeId, -1, - false); + result = coerce_type(tree, orig_typeId, target_typeId, + COERCION_IMPLICIT, COERCE_IMPLICIT_CAST); else result = tree; } @@ -191,6 +183,7 @@ make_var(ParseState *pstate, RangeTblEntry *rte, int attrno) * arrayBase Already-transformed expression for the array as a whole * (may be NULL if we are handling an INSERT) * arrayType OID of array's datatype + * arrayTypMod typmod to be applied to array elements * indirection Untransformed list of subscripts (must not be NIL) * forceSlice If true, treat subscript as array slice in all cases * assignFrom NULL for array fetch, else transformed expression for source. @@ -199,6 +192,7 @@ ArrayRef * transformArraySubscripts(ParseState *pstate, Node *arrayBase, Oid arrayType, + int32 arrayTypMod, List *indirection, bool forceSlice, Node *assignFrom) @@ -286,8 +280,10 @@ transformArraySubscripts(ParseState *pstate, { subexpr = transformExpr(pstate, ai->lidx); /* If it's not int4 already, try to coerce */ - subexpr = CoerceTargetExpr(pstate, subexpr, exprType(subexpr), - INT4OID, -1, false); + subexpr = coerce_to_target_type(subexpr, exprType(subexpr), + INT4OID, -1, + COERCION_ASSIGNMENT, + COERCE_IMPLICIT_CAST); if (subexpr == NULL) elog(ERROR, "array index expressions must be integers"); } @@ -306,8 +302,10 @@ transformArraySubscripts(ParseState *pstate, } subexpr = transformExpr(pstate, ai->uidx); /* If it's not int4 already, try to coerce */ - subexpr = CoerceTargetExpr(pstate, subexpr, exprType(subexpr), - INT4OID, -1, false); + subexpr = coerce_to_target_type(subexpr, exprType(subexpr), + INT4OID, -1, + COERCION_ASSIGNMENT, + COERCE_IMPLICIT_CAST); if (subexpr == NULL) elog(ERROR, "array index expressions must be integers"); upperIndexpr = lappend(upperIndexpr, subexpr); @@ -323,19 +321,16 @@ transformArraySubscripts(ParseState *pstate, if (typesource != InvalidOid) { - if (typesource != typeneeded) - { - /* XXX fixme: need to get the array's atttypmod? */ - assignFrom = CoerceTargetExpr(pstate, assignFrom, - typesource, typeneeded, - -1, false); - if (assignFrom == NULL) - elog(ERROR, "Array assignment requires type '%s'" - " but expression is of type '%s'" - "\n\tYou will need to rewrite or cast the expression", - format_type_be(typeneeded), - format_type_be(typesource)); - } + assignFrom = coerce_to_target_type(assignFrom, typesource, + typeneeded, arrayTypMod, + COERCION_ASSIGNMENT, + COERCE_IMPLICIT_CAST); + if (assignFrom == NULL) + elog(ERROR, "Array assignment requires type %s" + " but expression is of type %s" + "\n\tYou will need to rewrite or cast the expression", + format_type_be(typeneeded), + format_type_be(typesource)); } } @@ -344,7 +339,7 @@ transformArraySubscripts(ParseState *pstate, */ aref = makeNode(ArrayRef); aref->refrestype = resultType; /* XXX should save element type - * too */ + * OID too */ aref->refattrlength = type_struct_array->typlen; aref->refelemlength = type_struct_element->typlen; aref->refelembyval = type_struct_element->typbyval; @@ -373,21 +368,16 @@ transformArraySubscripts(ParseState *pstate, * 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. + * For integers and floats we produce int4, int8, or numeric depending + * on the value of the number. XXX This should include int2 as well, + * but additional cleanup is needed before we can do that; else cases + * like "WHERE int4var = 42" will fail to be indexable. */ Const * make_const(Value *value) { Datum val; + int64 val64; Oid typeid; int typelen; bool typebyval; @@ -404,12 +394,13 @@ make_const(Value *value) break; case T_Float: - if (fitsInFloat(value)) + /* could be an oversize integer as well as a float ... */ + if (scanint8(strVal(value), true, &val64)) { - val = Float8GetDatum(floatVal(value)); + val = Int64GetDatum(val64); - typeid = FLOAT8OID; - typelen = sizeof(float8); + typeid = INT8OID; + typelen = sizeof(int64); typebyval = false; /* XXX might change someday */ } else @@ -470,46 +461,3 @@ make_const(Value *value) 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((unsigned char) *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; -} |