diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 53bb27e3294d65f30ef36fe02d87999b208cd938..241b8ca10353332d0c2edf047fc1ad0d6fd5436d 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.99 2000/01/09 00:26:22 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.100 2000/01/17 00:14:46 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1385,6 +1385,17 @@ _copyTypeName(TypeName *from)
 	return newnode;
 }
 
+static TypeCast *
+_copyTypeCast(TypeCast *from)
+{
+	TypeCast   *newnode = makeNode(TypeCast);
+
+	Node_Copy(from, newnode, arg);
+	Node_Copy(from, newnode, typename);
+
+	return newnode;
+}
+
 static Query *
 _copyQuery(Query *from)
 {
@@ -1658,6 +1669,9 @@ copyObject(void *from)
 		case T_TypeName:
 			retval = _copyTypeName(from);
 			break;
+		case T_TypeCast:
+			retval = _copyTypeCast(from);
+			break;
 
 			/*
 			 * VALUE NODES
diff --git a/src/backend/nodes/freefuncs.c b/src/backend/nodes/freefuncs.c
index c11677b5b71f88e5eb8786c14159224f8434d581..83b05821ccc2095c9a660044e4ef07d16e7a6f65 100644
--- a/src/backend/nodes/freefuncs.c
+++ b/src/backend/nodes/freefuncs.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/nodes/Attic/freefuncs.c,v 1.30 2000/01/09 00:26:23 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/nodes/Attic/freefuncs.c,v 1.31 2000/01/17 00:14:47 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1046,6 +1046,15 @@ _freeTypeName(TypeName *node)
 	pfree(node);
 }
 
+static void
+_freeTypeCast(TypeCast *node)
+{
+	freeObject(node->arg);
+	freeObject(node->typename);
+
+	pfree(node);
+}
+
 static void
 _freeQuery(Query *node)
 {
@@ -1294,6 +1303,9 @@ freeObject(void *node)
 		case T_TypeName:
 			_freeTypeName(node);
 			break;
+		case T_TypeCast:
+			_freeTypeCast(node);
+			break;
 
 			/*
 			 * VALUE NODES
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 2bf112e309ae5c71de3d6e2d0b8cf2896e4a1cc6..08db66e3c6b21af3871560ea96c65dbe6605f403 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -5,7 +5,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- *	$Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.102 2000/01/14 00:53:21 tgl Exp $
+ *	$Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.103 2000/01/17 00:14:47 tgl Exp $
  *
  * NOTES
  *	  Every (plan) node in POSTGRES has an associated "out" routine which
@@ -190,6 +190,15 @@ _outTypeName(StringInfo str, TypeName *node)
 	_outNode(str, node->arrayBounds);
 }
 
+static void
+_outTypeCast(StringInfo str, TypeCast *node)
+{
+	appendStringInfo(str, " TYPECAST :arg ");
+	_outNode(str, node->arg);
+	appendStringInfo(str, " :typename ");
+	_outNode(str, node->typename);
+}
+
 static void
 _outIndexElem(StringInfo str, IndexElem *node)
 {
@@ -1292,6 +1301,8 @@ _outAConst(StringInfo str, A_Const *node)
 {
 	appendStringInfo(str, "CONST ");
 	_outValue(str, &(node->val));
+	appendStringInfo(str, " :typename ");
+	_outNode(str, node->typename);
 }
 
 static void
@@ -1400,6 +1411,9 @@ _outNode(StringInfo str, void *obj)
 			case T_TypeName:
 				_outTypeName(str, obj);
 				break;
+			case T_TypeCast:
+				_outTypeCast(str, obj);
+				break;
 			case T_IndexElem:
 				_outIndexElem(str, obj);
 				break;
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index a3a01d510f0492b3ec97ff1bf4bc0ea57738b660..c4901b4c51fd1b341922c0370306e146b70d51c4 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -1,4 +1,4 @@
-%{ /* -*-text-*- */
+%{
 
 /*#define YYDEBUG 1*/
 /*-------------------------------------------------------------------------
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.127 2000/01/16 20:04:55 petere Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.128 2000/01/17 00:14:48 tgl Exp $
  *
  * HISTORY
  *	  AUTHOR			DATE			MAJOR EVENT
@@ -71,6 +71,7 @@ static int	pfunc_num_args;
 static char *xlateSqlFunc(char *);
 static char *xlateSqlType(char *);
 static Node *makeA_Expr(int oper, char *opname, Node *lexpr, Node *rexpr);
+static Node *makeTypeCast(Node *arg, TypeName *typename);
 static Node *makeRowExpr(char *opr, List *largs, List *rargs);
 static void mapTargetColumns(List *source, List *target);
 static void param_type_init(Oid *typev, int nargs);
@@ -274,6 +275,8 @@ static Node *doNegate(Node *n);
  * This gets annoying when trying to also retain Postgres' nice
  *  type-extensible features, but we don't really have a choice.
  * - thomas 1997-10-11
+ * NOTE: Whenever possible, try to add new keywords to the ColId list,
+ * or failing that, at least to the ColLabel list.
  */
 
 /* Keywords (in SQL92 reserved words) */
@@ -3902,23 +3905,7 @@ MathOp:	'+'				{ $$ = "+"; }
 a_expr:  com_expr
 				{	$$ = $1;  }
 		| a_expr TYPECAST Typename
-				{
-					$$ = (Node *)$1;
-					/* AexprConst can be either A_Const or ParamNo */
-					if (nodeTag($1) == T_A_Const) {
-						((A_Const *)$1)->typename = $3;
-					} else if (nodeTag($1) == T_ParamNo) {
-						((ParamNo *)$1)->typename = $3;
-					/* otherwise, try to transform to a function call */
-					} else {
-						FuncCall *n = makeNode(FuncCall);
-						n->funcname = $3->name;
-						n->args = lcons($1,NIL);
-						n->agg_star = false;
-						n->agg_distinct = false;
-						$$ = (Node *)n;
-					}
-				}
+				{	$$ = makeTypeCast($1, $3); }
 		/*
 		 * Can't collapse this into prior rule by using a_expr_or_null;
 		 * that creates reduce/reduce conflicts.  Grumble.
@@ -4149,23 +4136,7 @@ a_expr:  com_expr
 b_expr:  com_expr
 				{	$$ = $1;  }
 		| b_expr TYPECAST Typename
-				{
-					$$ = (Node *)$1;
-					/* AexprConst can be either A_Const or ParamNo */
-					if (nodeTag($1) == T_A_Const) {
-						((A_Const *)$1)->typename = $3;
-					} else if (nodeTag($1) == T_ParamNo) {
-						((ParamNo *)$1)->typename = $3;
-					/* otherwise, try to transform to a function call */
-					} else {
-						FuncCall *n = makeNode(FuncCall);
-						n->funcname = $3->name;
-						n->args = lcons($1,NIL);
-						n->agg_star = false;
-						n->agg_distinct = false;
-						$$ = (Node *)n;
-					}
-				}
+				{	$$ = makeTypeCast($1, $3); }
 		| NULL_P TYPECAST Typename
 				{
 					A_Const *n = makeNode(A_Const);
@@ -4243,23 +4214,7 @@ com_expr:  attr
 		| '(' a_expr_or_null ')'
 				{	$$ = $2; }
 		| CAST '(' a_expr_or_null AS Typename ')'
-				{
-					$$ = (Node *)$3;
-					/* AexprConst can be either A_Const or ParamNo */
-					if (nodeTag($3) == T_A_Const) {
-						((A_Const *)$3)->typename = $5;
-					} else if (nodeTag($3) == T_ParamNo) {
-						((ParamNo *)$3)->typename = $5;
-					/* otherwise, try to transform to a function call */
-					} else {
-						FuncCall *n = makeNode(FuncCall);
-						n->funcname = $5->name;
-						n->args = lcons($3,NIL);
-						n->agg_star = false;
-						n->agg_distinct = false;
-						$$ = (Node *)n;
-					}
-				}
+				{	$$ = makeTypeCast($3, $5); }
 		| case_expr
 				{	$$ = $1; }
 		| func_name '(' ')'
@@ -5078,6 +5033,7 @@ ColLabel:  ColId						{ $$ = $1; }
 		| CONSTRAINT					{ $$ = "constraint"; }
 		| COPY							{ $$ = "copy"; }
 		| CURRENT						{ $$ = "current"; }
+		| DECIMAL						{ $$ = "decimal"; }
 		| DO							{ $$ = "do"; }
 		| ELSE							{ $$ = "else"; }
 		| END_TRANS						{ $$ = "end"; }
@@ -5095,6 +5051,7 @@ ColLabel:  ColId						{ $$ = $1; }
 		| NEW							{ $$ = "new"; }
 		| NONE							{ $$ = "none"; }
 		| NULLIF						{ $$ = "nullif"; }
+		| NUMERIC						{ $$ = "numeric"; }
 		| ORDER							{ $$ = "order"; }
 		| POSITION						{ $$ = "position"; }
 		| PRECISION						{ $$ = "precision"; }
@@ -5139,6 +5096,36 @@ makeA_Expr(int oper, char *opname, Node *lexpr, Node *rexpr)
 	return (Node *)a;
 }
 
+static Node *
+makeTypeCast(Node *arg, TypeName *typename)
+{
+	/*
+	 * If arg is an A_Const or ParamNo, just stick the typename into the
+	 * field reserved for it --- unless there's something there already!
+	 * (We don't want to collapse x::type1::type2 into just x::type2.)
+	 * Otherwise, generate a TypeCast node.
+	 */
+	if (IsA(arg, A_Const) &&
+		((A_Const *) arg)->typename == NULL)
+	{
+		((A_Const *) arg)->typename = typename;
+		return arg;
+	}
+	else if (IsA(arg, ParamNo) &&
+			 ((ParamNo *) arg)->typename == NULL)
+	{
+		((ParamNo *) arg)->typename = typename;
+		return arg;
+	}
+	else
+	{
+		TypeCast *n = makeNode(TypeCast);
+		n->arg = arg;
+		n->typename = typename;
+		return (Node *) n;
+	}
+}
+
 /* makeRowExpr()
  * Generate separate operator nodes for a single row descriptor expression.
  * Perhaps this should go deeper in the parser someday...
diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c
index 6ddc090bb0b221199f16ef579c919bc35b509464..2d0c4b1d2af653f0686acb1d23d5673456879de5 100644
--- a/src/backend/parser/parse_coerce.c
+++ b/src/backend/parser/parse_coerce.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.27 2000/01/10 17:14:36 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.28 2000/01/17 00:14:48 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -32,8 +32,8 @@ static Oid	PreferredType(CATEGORY category, Oid type);
  * Convert a function argument to a different type.
  */
 Node *
-coerce_type(ParseState *pstate, Node *node, Oid inputTypeId, Oid targetTypeId,
-			int32 atttypmod)
+coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
+			Oid targetTypeId, int32 atttypmod)
 {
 	Node	   *result = NULL;
 
@@ -200,6 +200,70 @@ can_coerce_type(int nargs, Oid *input_typeids, Oid *func_typeids)
 	return true;
 }
 
+/* coerce_type_typmod()
+ * Force a value to a particular typmod, if meaningful and possible.
+ *
+ * This is applied to values that are going to be stored in a relation
+ * (where we have an atttypmod for the column) as well as values being
+ * explicitly CASTed (where the typmod comes from the target type spec).
+ *
+ * The caller must have already ensured that the value is of the correct
+ * type, typically by applying coerce_type.
+ *
+ * If the target column type possesses a function named for the type
+ * and having parameter signature (columntype, int4), we assume that
+ * the type requires coercion to its own length and that the said
+ * function should be invoked to do that.
+ *
+ * "bpchar" (ie, char(N)) and "numeric" are examples of such types.
+ */
+Node *
+coerce_type_typmod(ParseState *pstate, Node *node,
+				   Oid targetTypeId, int32 atttypmod)
+{
+	char	   *funcname;
+	Oid			oid_array[FUNC_MAX_ARGS];
+	HeapTuple	ftup;
+
+	/*
+	 * We assume that only typmod values greater than 0 indicate a forced
+	 * conversion is necessary.
+	 */
+	if (atttypmod <= 0 ||
+		atttypmod == exprTypmod(node))
+		return node;
+
+	funcname = typeidTypeName(targetTypeId);
+	MemSet(oid_array, 0, FUNC_MAX_ARGS * sizeof(Oid));
+	oid_array[0] = targetTypeId;
+	oid_array[1] = INT4OID;
+
+	/* attempt to find with arguments exactly as specified... */
+	ftup = SearchSysCacheTuple(PROCNAME,
+							   PointerGetDatum(funcname),
+							   Int32GetDatum(2),
+							   PointerGetDatum(oid_array),
+							   0);
+
+	if (HeapTupleIsValid(ftup))
+	{
+		A_Const    *cons = makeNode(A_Const);
+		FuncCall   *func = makeNode(FuncCall);
+
+		cons->val.type = T_Integer;
+		cons->val.val.ival = atttypmod;
+
+		func->funcname = funcname;
+		func->args = lappend(lcons(node, NIL), cons);
+		func->agg_star = false;
+		func->agg_distinct = false;
+
+		node = transformExpr(pstate, (Node *) func, EXPR_COLUMN_FIRST);
+	}
+
+	return node;
+}
+
 
 /* TypeCategory()
  * Assign a category to the specified OID.
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index 2b0414f8029821b7f1f50f702d7bfa69b1a76988..6fe43e9e0233f152a0d29b08af157849e9249890 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;
+}
diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c
index 503f544e9edf6fe6842bdcf7f4f589261533291b..f80b6ef4fbb85bb71e043fc6f75e2ff3dd7c29d7 100644
--- a/src/backend/parser/parse_target.c
+++ b/src/backend/parser/parse_target.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.51 2000/01/10 17:14:36 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.52 2000/01/17 00:14:48 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -24,8 +24,6 @@
 #include "utils/syscache.h"
 
 
-static Node *SizeTargetExpr(ParseState *pstate, Node *expr,
-							Oid attrtype, int32 attrtypmod);
 static List *ExpandAllTables(ParseState *pstate);
 static char *FigureColname(Node *expr, Node *resval);
 
@@ -245,9 +243,7 @@ updateTargetListEntry(ParseState *pstate,
 			 * If the target is a fixed-length type, it may need a length
 			 * coercion as well as a type coercion.
 			 */
-			if (attrtypmod > 0 &&
-				attrtypmod != exprTypmod(tle->expr))
-				tle->expr = SizeTargetExpr(pstate, tle->expr,
+			tle->expr = coerce_type_typmod(pstate, tle->expr,
 										   attrtype, attrtypmod);
 		}
 	}
@@ -300,61 +296,6 @@ CoerceTargetExpr(ParseState *pstate,
 }
 
 
-/*
- * SizeTargetExpr()
- *
- * If the target column type possesses a function named for the type
- * and having parameter signature (columntype, int4), we assume that
- * the type requires coercion to its own length and that the said
- * function should be invoked to do that.
- *
- * Currently, "bpchar" (ie, char(N)) is the only such type, but try
- * to be more general than a hard-wired test...
- */
-static Node *
-SizeTargetExpr(ParseState *pstate,
-			   Node *expr,
-			   Oid attrtype,
-			   int32 attrtypmod)
-{
-	char	   *funcname;
-	Oid			oid_array[FUNC_MAX_ARGS];
-	HeapTuple	ftup;
-	int			i;
-
-	funcname = typeidTypeName(attrtype);
-	oid_array[0] = attrtype;
-	oid_array[1] = INT4OID;
-	for (i = 2; i < FUNC_MAX_ARGS; i++)
-		oid_array[i] = InvalidOid;
-
-	/* attempt to find with arguments exactly as specified... */
-	ftup = SearchSysCacheTuple(PROCNAME,
-							   PointerGetDatum(funcname),
-							   Int32GetDatum(2),
-							   PointerGetDatum(oid_array),
-							   0);
-
-	if (HeapTupleIsValid(ftup))
-	{
-		A_Const    *cons = makeNode(A_Const);
-		FuncCall   *func = makeNode(FuncCall);
-
-		cons->val.type = T_Integer;
-		cons->val.val.ival = attrtypmod;
-
-		func->funcname = funcname;
-		func->args = lappend(lcons(expr, NIL), cons);
-		func->agg_star = false;
-		func->agg_distinct = false;
-
-		expr = transformExpr(pstate, (Node *) func, EXPR_COLUMN_FIRST);
-	}
-
-	return expr;
-}
-
-
 /*
  * checkInsertTargets -
  *	  generate a list of column names if not supplied or
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index 219bcbe6f6aa5add7f6d069eec9ab618bf97701f..a6df5f1417a41f85a003bf542417d444f53718c3 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: nodes.h,v 1.61 2000/01/16 20:04:58 petere Exp $
+ * $Id: nodes.h,v 1.62 2000/01/17 00:14:48 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -202,7 +202,7 @@ typedef enum NodeTag
 	T_FuncCall,
 	T_A_Indices,
 	T_ResTarget,
-	T_ParamString,		/* not used anymore */
+	T_TypeCast,
 	T_RelExpr,
 	T_SortGroupBy,
 	T_RangeVar,
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 53c55be4db7bdafc9db88b1292c6b53789940dce..b1fc802d88337bf82ea2d47a067c1633d7786316 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: parsenodes.h,v 1.94 2000/01/16 20:04:58 petere Exp $
+ * $Id: parsenodes.h,v 1.95 2000/01/17 00:14:48 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -868,6 +868,22 @@ typedef struct A_Const
 	TypeName   *typename;		/* typecast */
 } A_Const;
 
+/*
+ * TypeCast - a CAST expression
+ *
+ * NOTE: for mostly historical reasons, A_Const and ParamNo parsenodes contain
+ * room for a TypeName; we only generate a separate TypeCast node if the
+ * argument to be casted is neither of those kinds of nodes.  In theory either
+ * representation would work, but it is convenient (especially for A_Const)
+ * to have the target type immediately available.
+ */
+typedef struct TypeCast
+{
+	NodeTag		type;
+	Node	   *arg;			/* the expression being casted */
+	TypeName   *typename;		/* the target type */
+} TypeCast;
+
 /*
  * CaseExpr - a CASE expression
  */
diff --git a/src/include/parser/parse_coerce.h b/src/include/parser/parse_coerce.h
index 02a1eed11e7060a99cde482cbee5c3dc8797e559..06736c6dff9acd6d34df5d5b091ece7f165a8b36 100644
--- a/src/include/parser/parse_coerce.h
+++ b/src/include/parser/parse_coerce.h
@@ -2,11 +2,11 @@
  *
  * parse_coerce.h
  *
- *
+ *	Routines for type coercion.
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: parse_coerce.h,v 1.15 1999/07/16 17:07:36 momjian Exp $
+ * $Id: parse_coerce.h,v 1.16 2000/01/17 00:14:49 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -125,6 +125,8 @@ extern CATEGORY TypeCategory(Oid type);
 
 extern bool can_coerce_type(int nargs, Oid *input_typeids, Oid *func_typeids);
 extern Node *coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
-			Oid targetTypeId, int32 atttypmod);
+						 Oid targetTypeId, int32 atttypmod);
+extern Node *coerce_type_typmod(ParseState *pstate, Node *node,
+								Oid targetTypeId, int32 atttypmod);
 
 #endif	 /* PARSE_COERCE_H */