1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-13 07:41:39 +03:00

Create a new parsetree node type, TypeCast, so that transformation of

SQL cast constructs can be performed during expression transformation
instead of during parsing.  This allows constructs like x::numeric(9,2)
and x::int2::float8 to behave as one would expect.
This commit is contained in:
Tom Lane
2000-01-17 00:14:49 +00:00
parent e0bd60171a
commit 49528361f5
10 changed files with 242 additions and 132 deletions

View File

@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.64 2000/01/16 05:18:19 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.65 2000/01/17 00:14:48 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -29,7 +29,9 @@
#include "parser/parse_target.h"
#include "utils/builtins.h"
static Node *parser_typecast(Value *expr, TypeName *typename, int32 atttypmod);
static Node *parser_typecast_constant(Value *expr, TypeName *typename);
static Node *parser_typecast_expression(ParseState *pstate,
Node *expr, TypeName *typename);
static Node *transformAttr(ParseState *pstate, Attr *att, int precedence);
static Node *transformIdent(ParseState *pstate, Ident *ident, int precedence);
static Node *transformIndirection(ParseState *pstate, Node *basenode,
@ -63,7 +65,7 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
Value *val = &con->val;
if (con->typename != NULL)
result = parser_typecast(val, con->typename, con->typename->typmod);
result = parser_typecast_constant(val, con->typename);
else
result = (Node *) make_const(val);
break;
@ -85,6 +87,15 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
param->param_tlist = (List *) NULL;
result = transformIndirection(pstate, (Node *) param,
pno->indirection);
/* XXX what about cast (typename) applied to Param ??? */
break;
}
case T_TypeCast:
{
TypeCast *tc = (TypeCast *) expr;
Node *arg = transformExpr(pstate, tc->arg, precedence);
result = parser_typecast_expression(pstate, arg, tc->typename);
break;
}
case T_A_Expr:
@ -689,7 +700,7 @@ exprTypmod(Node *expr)
* by the parser and an explicit type name to cast to.
*/
static Node *
parser_typecast(Value *expr, TypeName *typename, int32 atttypmod)
parser_typecast_constant(Value *expr, TypeName *typename)
{
Const *con;
Type tp;
@ -716,7 +727,7 @@ parser_typecast(Value *expr, TypeName *typename, int32 atttypmod)
break;
default:
elog(ERROR,
"parser_typecast: cannot cast this expression to type '%s'",
"parser_typecast_constant: cannot cast this expression to type '%s'",
typename->name);
}
@ -733,7 +744,7 @@ parser_typecast(Value *expr, TypeName *typename, int32 atttypmod)
if (isNull)
datum = (Datum) NULL;
else
datum = stringTypeDatum(tp, const_string, atttypmod);
datum = stringTypeDatum(tp, const_string, typename->typmod);
con = makeConst(typeTypeId(tp),
typeLen(tp),
@ -748,3 +759,52 @@ parser_typecast(Value *expr, TypeName *typename, int32 atttypmod)
return (Node *) con;
}
/*
* Handle an explicit CAST applied to a non-constant expression.
* (Actually, this works for constants too, but gram.y won't generate
* a TypeCast node if the argument is just a constant.)
*
* The given expr has already been transformed, but we need to lookup
* the type name and then apply any necessary coercion function(s).
*/
static Node *
parser_typecast_expression(ParseState *pstate,
Node *expr, TypeName *typename)
{
Oid inputType = exprType(expr);
Type tp;
Oid targetType;
if (typename->arrayBounds != NIL)
{
char type_string[NAMEDATALEN+2];
sprintf(type_string, "_%s", typename->name);
tp = (Type) typenameType(type_string);
}
else
tp = (Type) typenameType(typename->name);
targetType = typeTypeId(tp);
if (inputType == InvalidOid)
return expr; /* do nothing if NULL input */
if (inputType != targetType)
{
expr = CoerceTargetExpr(pstate, expr,
inputType, targetType);
if (expr == NULL)
elog(ERROR, "Cannot cast type '%s' to '%s'",
typeidTypeName(inputType),
typeidTypeName(targetType));
}
/*
* If the target is a fixed-length type, it may need a length
* coercion as well as a type coercion.
*/
expr = coerce_type_typmod(pstate, expr,
targetType, typename->typmod);
return expr;
}