aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser/parse_expr.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2000-01-17 00:14:49 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2000-01-17 00:14:49 +0000
commit49528361f521b432da2cfafcb81cade17eb324d1 (patch)
treec4b653e509b635292cc0fa0847a149c1dfdfd518 /src/backend/parser/parse_expr.c
parente0bd60171a26e6a324989a5b649dd08e8e77ed7e (diff)
downloadpostgresql-49528361f521b432da2cfafcb81cade17eb324d1.tar.gz
postgresql-49528361f521b432da2cfafcb81cade17eb324d1.zip
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.
Diffstat (limited to 'src/backend/parser/parse_expr.c')
-rw-r--r--src/backend/parser/parse_expr.c72
1 files changed, 66 insertions, 6 deletions
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index 2b0414f8029..6fe43e9e023 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -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;
+}