From 43bfffcbc39f540c10ef62dd8afe77e0352bc89b Mon Sep 17 00:00:00 2001
From: Franck Verrot <franck@verrot.fr>
Date: Sun, 28 Jun 2015 11:03:31 +0200
Subject: [PATCH] Provide more into the varchar constraint validator

---
 src/backend/catalog/heap.c             |  3 +-
 src/backend/commands/prepare.c         |  3 +-
 src/backend/commands/tablecmds.c       |  9 ++++--
 src/backend/optimizer/prep/preptlist.c |  4 ++-
 src/backend/parser/parse_clause.c      | 10 +++---
 src/backend/parser/parse_coerce.c      | 58 ++++++++++++++++++++++------------
 src/backend/parser/parse_expr.c        |  9 ++++--
 src/backend/parser/parse_func.c        | 16 ++++++----
 src/backend/parser/parse_node.c        |  9 ++++--
 src/backend/parser/parse_target.c      |  9 ++++--
 src/backend/rewrite/rewriteHandler.c   |  9 ++++--
 src/backend/rewrite/rewriteManip.c     |  3 +-
 src/backend/utils/adt/varchar.c        |  8 +++--
 src/include/parser/parse_coerce.h      |  7 ++--
 src/pl/plpgsql/src/pl_exec.c           |  6 ++--
 15 files changed, 106 insertions(+), 57 deletions(-)

diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index d04e94d..19c7a6d 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -2584,7 +2584,8 @@ cookDefault(ParseState *pstate,
 									 atttypid, atttypmod,
 									 COERCION_ASSIGNMENT,
 									 COERCE_IMPLICIT_CAST,
-									 -1);
+									 -1,
+									 attname);
 		if (expr == NULL)
 			ereport(ERROR,
 					(errcode(ERRCODE_DATATYPE_MISMATCH),
diff --git a/src/backend/commands/prepare.c b/src/backend/commands/prepare.c
index fb33d30..99a1bb7 100644
--- a/src/backend/commands/prepare.c
+++ b/src/backend/commands/prepare.c
@@ -362,7 +362,8 @@ EvaluateParams(PreparedStatement *pstmt, List *params,
 									 expected_type_id, -1,
 									 COERCION_ASSIGNMENT,
 									 COERCE_IMPLICIT_CAST,
-									 -1);
+									 -1,
+									 NULL);
 
 		if (expr == NULL)
 			ereport(ERROR,
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 84dbee0..1dc5f09 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -4919,7 +4919,8 @@ ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel,
 													typmod,
 													COERCION_ASSIGNMENT,
 													COERCE_IMPLICIT_CAST,
-													-1);
+													-1,
+													NULL);
 			if (defval == NULL) /* should not happen */
 				elog(ERROR, "failed to coerce base type to domain");
 		}
@@ -7886,7 +7887,8 @@ ATPrepAlterColumnType(List **wqueue,
 										  targettype, targettypmod,
 										  COERCION_ASSIGNMENT,
 										  COERCE_IMPLICIT_CAST,
-										  -1);
+										  -1,
+										  colName);
 		if (transform == NULL)
 			ereport(ERROR,
 					(errcode(ERRCODE_DATATYPE_MISMATCH),
@@ -8060,7 +8062,8 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
 											targettype, targettypmod,
 											COERCION_ASSIGNMENT,
 											COERCE_IMPLICIT_CAST,
-											-1);
+											-1,
+											NULL);
 		if (defaultexpr == NULL)
 			ereport(ERROR,
 					(errcode(ERRCODE_DATATYPE_MISMATCH),
diff --git a/src/backend/optimizer/prep/preptlist.c b/src/backend/optimizer/prep/preptlist.c
index 6b0c689..bc5bd62 100644
--- a/src/backend/optimizer/prep/preptlist.c
+++ b/src/backend/optimizer/prep/preptlist.c
@@ -276,6 +276,7 @@ expand_targetlist(List *tlist, int command_type,
 			Oid			attcollation = att_tup->attcollation;
 			Node	   *new_expr;
 
+      //RelationGetRelationName
 			switch (command_type)
 			{
 				case CMD_INSERT:
@@ -294,7 +295,8 @@ expand_targetlist(List *tlist, int command_type,
 													COERCE_IMPLICIT_CAST,
 													-1,
 													false,
-													false);
+													false,
+													NULL);
 					}
 					else
 					{
diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c
index e90e1d6..3b94fe1 100644
--- a/src/backend/parser/parse_clause.c
+++ b/src/backend/parser/parse_clause.c
@@ -1232,7 +1232,7 @@ buildMergedJoinVar(ParseState *pstate, JoinType jointype,
 	if (l_colvar->vartype != outcoltype)
 		l_node = coerce_type(pstate, (Node *) l_colvar, l_colvar->vartype,
 							 outcoltype, outcoltypmod,
-							 COERCION_IMPLICIT, COERCE_IMPLICIT_CAST, -1);
+							 COERCION_IMPLICIT, COERCE_IMPLICIT_CAST, -1, NULL);
 	else if (l_colvar->vartypmod != outcoltypmod)
 		l_node = (Node *) makeRelabelType((Expr *) l_colvar,
 										  outcoltype, outcoltypmod,
@@ -1244,7 +1244,7 @@ buildMergedJoinVar(ParseState *pstate, JoinType jointype,
 	if (r_colvar->vartype != outcoltype)
 		r_node = coerce_type(pstate, (Node *) r_colvar, r_colvar->vartype,
 							 outcoltype, outcoltypmod,
-							 COERCION_IMPLICIT, COERCE_IMPLICIT_CAST, -1);
+							 COERCION_IMPLICIT, COERCE_IMPLICIT_CAST, -1, NULL);
 	else if (r_colvar->vartypmod != outcoltypmod)
 		r_node = (Node *) makeRelabelType((Expr *) r_colvar,
 										  outcoltype, outcoltypmod,
@@ -2871,7 +2871,8 @@ addTargetToSortList(ParseState *pstate, TargetEntry *tle,
 										 restype, TEXTOID, -1,
 										 COERCION_IMPLICIT,
 										 COERCE_IMPLICIT_CAST,
-										 -1);
+										 -1,
+										 NULL);
 		restype = TEXTOID;
 	}
 
@@ -3014,7 +3015,8 @@ addTargetToGroupList(ParseState *pstate, TargetEntry *tle,
 										 restype, TEXTOID, -1,
 										 COERCION_IMPLICIT,
 										 COERCE_IMPLICIT_CAST,
-										 -1);
+										 -1,
+										 NULL);
 		restype = TEXTOID;
 	}
 
diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c
index f6e7be4..184dcab 100644
--- a/src/backend/parser/parse_coerce.c
+++ b/src/backend/parser/parse_coerce.c
@@ -34,14 +34,15 @@
 static Node *coerce_type_typmod(Node *node,
 				   Oid targetTypeId, int32 targetTypMod,
 				   CoercionForm cformat, int location,
-				   bool isExplicit, bool hideInputCoercion);
+				   bool isExplicit, bool hideInputCoercion, char *colname);
 static void hide_coercion_node(Node *node);
 static Node *build_coercion_expression(Node *node,
 						  CoercionPathType pathtype,
 						  Oid funcId,
 						  Oid targetTypeId, int32 targetTypMod,
 						  CoercionForm cformat, int location,
-						  bool isExplicit);
+						  bool isExplicit,
+						  char *colname);
 static Node *coerce_record_to_complex(ParseState *pstate, Node *node,
 						 Oid targetTypeId,
 						 CoercionContext ccontext,
@@ -77,7 +78,8 @@ coerce_to_target_type(ParseState *pstate, Node *expr, Oid exprtype,
 					  Oid targettype, int32 targettypmod,
 					  CoercionContext ccontext,
 					  CoercionForm cformat,
-					  int location)
+					  int location,
+					  char *colname)
 {
 	Node	   *result;
 	Node	   *origexpr;
@@ -100,7 +102,7 @@ coerce_to_target_type(ParseState *pstate, Node *expr, Oid exprtype,
 
 	result = coerce_type(pstate, expr, exprtype,
 						 targettype, targettypmod,
-						 ccontext, cformat, location);
+						 ccontext, cformat, location, colname);
 
 	/*
 	 * If the target is a fixed-length type, it may need a length coercion as
@@ -111,7 +113,8 @@ coerce_to_target_type(ParseState *pstate, Node *expr, Oid exprtype,
 								targettype, targettypmod,
 								cformat, location,
 								(cformat != COERCE_IMPLICIT_CAST),
-								(result != expr && !IsA(result, Const)));
+								(result != expr && !IsA(result, Const)),
+								colname);
 
 	if (expr != origexpr)
 	{
@@ -154,7 +157,7 @@ coerce_to_target_type(ParseState *pstate, Node *expr, Oid exprtype,
 Node *
 coerce_type(ParseState *pstate, Node *node,
 			Oid inputTypeId, Oid targetTypeId, int32 targetTypeMod,
-			CoercionContext ccontext, CoercionForm cformat, int location)
+			CoercionContext ccontext, CoercionForm cformat, int location, char *colname)
 {
 	Node	   *result;
 	CoercionPathType pathtype;
@@ -317,7 +320,7 @@ coerce_type(ParseState *pstate, Node *node,
 			result = coerce_to_domain(result,
 									  baseTypeId, baseTypeMod,
 									  targetTypeId,
-									  cformat, location, false, false);
+									  cformat, location, false, false, colname);
 
 		ReleaseSysCache(baseType);
 
@@ -353,7 +356,7 @@ coerce_type(ParseState *pstate, Node *node,
 		newcoll->arg = (Expr *)
 			coerce_type(pstate, (Node *) coll->arg,
 						inputTypeId, targetTypeId, targetTypeMod,
-						ccontext, cformat, location);
+						ccontext, cformat, location, colname);
 		newcoll->collOid = coll->collOid;
 		newcoll->location = coll->location;
 		return (Node *) newcoll;
@@ -380,7 +383,7 @@ coerce_type(ParseState *pstate, Node *node,
 			result = build_coercion_expression(node, pathtype, funcId,
 											   baseTypeId, baseTypeMod,
 											   cformat, location,
-										  (cformat != COERCE_IMPLICIT_CAST));
+										  (cformat != COERCE_IMPLICIT_CAST), colname);
 
 			/*
 			 * If domain, coerce to the domain type and relabel with domain
@@ -391,8 +394,8 @@ coerce_type(ParseState *pstate, Node *node,
 				result = coerce_to_domain(result, baseTypeId, baseTypeMod,
 										  targetTypeId,
 										  cformat, location, true,
-										  exprIsLengthCoercion(result,
-															   NULL));
+										  exprIsLengthCoercion(result, NULL),
+										  colname);
 		}
 		else
 		{
@@ -406,7 +409,7 @@ coerce_type(ParseState *pstate, Node *node,
 			 * then we won't need a RelabelType node.
 			 */
 			result = coerce_to_domain(node, InvalidOid, -1, targetTypeId,
-									  cformat, location, false, false);
+									  cformat, location, false, false, colname);
 			if (result == node)
 			{
 				/*
@@ -610,7 +613,7 @@ Node *
 coerce_to_domain(Node *arg, Oid baseTypeId, int32 baseTypeMod, Oid typeId,
 				 CoercionForm cformat, int location,
 				 bool hideInputCoercion,
-				 bool lengthCoercionDone)
+				 bool lengthCoercionDone, char *colname)
 {
 	CoerceToDomain *result;
 
@@ -645,7 +648,7 @@ coerce_to_domain(Node *arg, Oid baseTypeId, int32 baseTypeMod, Oid typeId,
 			arg = coerce_type_typmod(arg, baseTypeId, baseTypeMod,
 									 COERCE_IMPLICIT_CAST, location,
 									 (cformat != COERCE_IMPLICIT_CAST),
-									 false);
+									 false, colname);
 	}
 
 	/*
@@ -689,7 +692,7 @@ coerce_to_domain(Node *arg, Oid baseTypeId, int32 baseTypeMod, Oid typeId,
 static Node *
 coerce_type_typmod(Node *node, Oid targetTypeId, int32 targetTypMod,
 				   CoercionForm cformat, int location,
-				   bool isExplicit, bool hideInputCoercion)
+				   bool isExplicit, bool hideInputCoercion, char *colname)
 {
 	CoercionPathType pathtype;
 	Oid			funcId;
@@ -712,7 +715,8 @@ coerce_type_typmod(Node *node, Oid targetTypeId, int32 targetTypMod,
 		node = build_coercion_expression(node, pathtype, funcId,
 										 targetTypeId, targetTypMod,
 										 cformat, location,
-										 isExplicit);
+										 isExplicit,
+										 colname);
 	}
 
 	return node;
@@ -762,7 +766,8 @@ build_coercion_expression(Node *node,
 						  Oid funcId,
 						  Oid targetTypeId, int32 targetTypMod,
 						  CoercionForm cformat, int location,
-						  bool isExplicit)
+						  bool isExplicit,
+						  char *colname)
 {
 	int			nargs = 0;
 
@@ -834,6 +839,17 @@ build_coercion_expression(Node *node,
 			args = lappend(args, cons);
 		}
 
+		/* Pass it the column name for eventual display */
+		cons = makeConst(CSTRINGOID,
+						 -1,
+						 InvalidOid,
+						 strlen(colname),
+						 CStringGetDatum(colname),
+						 false,
+						 true);
+
+		args = lappend(args, cons);
+
 		fexpr = makeFuncExpr(funcId, targetTypeId, args,
 							 InvalidOid, InvalidOid, cformat);
 		fexpr->location = location;
@@ -974,7 +990,7 @@ coerce_record_to_complex(ParseState *pstate, Node *node,
 									  tupdesc->attrs[i]->atttypmod,
 									  ccontext,
 									  COERCE_IMPLICIT_CAST,
-									  -1);
+									  -1, NULL);
 		if (cexpr == NULL)
 			ereport(ERROR,
 					(errcode(ERRCODE_CANNOT_COERCE),
@@ -1034,7 +1050,7 @@ coerce_to_boolean(ParseState *pstate, Node *node,
 										BOOLOID, -1,
 										COERCION_ASSIGNMENT,
 										COERCE_IMPLICIT_CAST,
-										-1);
+										-1, NULL);
 		if (newnode == NULL)
 			ereport(ERROR,
 					(errcode(ERRCODE_DATATYPE_MISMATCH),
@@ -1081,7 +1097,7 @@ coerce_to_specific_type(ParseState *pstate, Node *node,
 										targetTypeId, -1,
 										COERCION_ASSIGNMENT,
 										COERCE_IMPLICIT_CAST,
-										-1);
+										-1, NULL);
 		if (newnode == NULL)
 			ereport(ERROR,
 					(errcode(ERRCODE_DATATYPE_MISMATCH),
@@ -1281,7 +1297,7 @@ coerce_to_common_type(ParseState *pstate, Node *node,
 		return node;			/* no work */
 	if (can_coerce_type(1, &inputTypeId, &targetTypeId, COERCION_IMPLICIT))
 		node = coerce_type(pstate, node, inputTypeId, targetTypeId, -1,
-						   COERCION_IMPLICIT, COERCE_IMPLICIT_CAST, -1);
+						   COERCION_IMPLICIT, COERCE_IMPLICIT_CAST, -1, NULL);
 	else
 		ereport(ERROR,
 				(errcode(ERRCODE_CANNOT_COERCE),
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index 0ff46dd..f724efc 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -2007,7 +2007,8 @@ transformArrayExpr(ParseState *pstate, A_ArrayExpr *a,
 										 typmod,
 										 COERCION_EXPLICIT,
 										 COERCE_EXPLICIT_CAST,
-										 -1);
+										 -1,
+										 NULL);
 			if (newe == NULL)
 				ereport(ERROR,
 						(errcode(ERRCODE_CANNOT_COERCE),
@@ -2308,7 +2309,8 @@ transformXmlSerialize(ParseState *pstate, XmlSerialize *xs)
 								   TEXTOID, targetType, targetTypmod,
 								   COERCION_IMPLICIT,
 								   COERCE_IMPLICIT_CAST,
-								   -1);
+								   -1,
+								   NULL);
 	if (result == NULL)
 		ereport(ERROR,
 				(errcode(ERRCODE_CANNOT_COERCE),
@@ -2520,7 +2522,8 @@ transformTypeCast(ParseState *pstate, TypeCast *tc)
 								   targetType, targetTypmod,
 								   COERCION_EXPLICIT,
 								   COERCE_EXPLICIT_CAST,
-								   location);
+								   location,
+								   NULL);
 	if (result == NULL)
 		ereport(ERROR,
 				(errcode(ERRCODE_CANNOT_COERCE),
diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c
index fa9761b..b3d0c54 100644
--- a/src/backend/parser/parse_func.c
+++ b/src/backend/parser/parse_func.c
@@ -258,7 +258,7 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
 		 */
 		return coerce_type(pstate, linitial(fargs),
 						   actual_arg_types[0], rettype, -1,
-						   COERCION_EXPLICIT, COERCE_EXPLICIT_CALL, location);
+						   COERCION_EXPLICIT, COERCE_EXPLICIT_CALL, location, NULL);
 	}
 	else if (fdresult == FUNCDETAIL_NORMAL)
 	{
@@ -898,7 +898,7 @@ ParseTableSample(ParseState *pstate, char *samplemethod, Node *repeatable,
 						 parser_errposition(pstate, exprLocation(inarg))));
 
 			arg = coerce_type(pstate, arg, argtype, init_arg_types[nargs], -1,
-							  COERCION_IMPLICIT, COERCE_IMPLICIT_CAST, -1);
+							  COERCION_IMPLICIT, COERCE_IMPLICIT_CAST, -1, NULL);
 		}
 
 		fargs = lappend(fargs, arg);
@@ -1788,7 +1788,8 @@ unify_hypothetical_args(ParseState *pstate,
 							  commontype, -1,
 							  COERCION_IMPLICIT,
 							  COERCE_IMPLICIT_CAST,
-							  -1);
+							  -1,
+							  NULL);
 		actual_arg_types[i] = commontype;
 		args[aargpos] = coerce_type(pstate,
 									args[aargpos],
@@ -1796,7 +1797,8 @@ unify_hypothetical_args(ParseState *pstate,
 									commontype, -1,
 									COERCION_IMPLICIT,
 									COERCE_IMPLICIT_CAST,
-									-1);
+									-1,
+									NULL);
 		actual_arg_types[aargpos] = commontype;
 	}
 
@@ -1852,7 +1854,8 @@ make_fn_arguments(ParseState *pstate,
 								   declared_arg_types[i], -1,
 								   COERCION_IMPLICIT,
 								   COERCE_IMPLICIT_CAST,
-								   -1);
+								   -1,
+								   NULL);
 				na->arg = (Expr *) node;
 			}
 			else
@@ -1863,7 +1866,8 @@ make_fn_arguments(ParseState *pstate,
 								   declared_arg_types[i], -1,
 								   COERCION_IMPLICIT,
 								   COERCE_IMPLICIT_CAST,
-								   -1);
+								   -1,
+								   NULL);
 				lfirst(current_fargs) = node;
 			}
 		}
diff --git a/src/backend/parser/parse_node.c b/src/backend/parser/parse_node.c
index 4130cbf..52e3ec1 100644
--- a/src/backend/parser/parse_node.c
+++ b/src/backend/parser/parse_node.c
@@ -349,7 +349,8 @@ transformArraySubscripts(ParseState *pstate,
 												INT4OID, -1,
 												COERCION_ASSIGNMENT,
 												COERCE_IMPLICIT_CAST,
-												-1);
+												-1,
+												NULL);
 				if (subexpr == NULL)
 					ereport(ERROR,
 							(errcode(ERRCODE_DATATYPE_MISMATCH),
@@ -376,7 +377,8 @@ transformArraySubscripts(ParseState *pstate,
 										INT4OID, -1,
 										COERCION_ASSIGNMENT,
 										COERCE_IMPLICIT_CAST,
-										-1);
+										-1,
+										NULL);
 		if (subexpr == NULL)
 			ereport(ERROR,
 					(errcode(ERRCODE_DATATYPE_MISMATCH),
@@ -400,7 +402,8 @@ transformArraySubscripts(ParseState *pstate,
 										typeneeded, arrayTypMod,
 										COERCION_ASSIGNMENT,
 										COERCE_IMPLICIT_CAST,
-										-1);
+										-1,
+										NULL);
 		if (newFrom == NULL)
 			ereport(ERROR,
 					(errcode(ERRCODE_DATATYPE_MISMATCH),
diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c
index 1b3fcd6..c14bd5c 100644
--- a/src/backend/parser/parse_target.c
+++ b/src/backend/parser/parse_target.c
@@ -516,7 +516,8 @@ transformAssignedExpr(ParseState *pstate,
 								  attrtype, attrtypmod,
 								  COERCION_ASSIGNMENT,
 								  COERCE_IMPLICIT_CAST,
-								  -1);
+								  -1,
+								  colname);
 		if (expr == NULL)
 			ereport(ERROR,
 					(errcode(ERRCODE_DATATYPE_MISMATCH),
@@ -764,7 +765,8 @@ transformAssignmentIndirection(ParseState *pstate,
 								   targetTypeId, targetTypMod,
 								   COERCION_ASSIGNMENT,
 								   COERCE_IMPLICIT_CAST,
-								   -1);
+								   -1,
+								   "foo indirection");
 	if (result == NULL)
 	{
 		if (targetIsArray)
@@ -866,7 +868,8 @@ transformAssignmentSubscripts(ParseState *pstate,
 									   targetTypeId, targetTypMod,
 									   COERCION_ASSIGNMENT,
 									   COERCE_IMPLICIT_CAST,
-									   -1);
+									   -1,
+									   "foo subscript");
 		/* can fail if we had int2vector/oidvector, but not for true domains */
 		if (result == NULL)
 			ereport(ERROR,
diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c
index bbd6b77..e5a55e3 100644
--- a/src/backend/rewrite/rewriteHandler.c
+++ b/src/backend/rewrite/rewriteHandler.c
@@ -811,7 +811,8 @@ rewriteTargetListIU(List *targetList,
 												COERCE_IMPLICIT_CAST,
 												-1,
 												false,
-												false);
+												false,
+												NULL);
 				}
 			}
 
@@ -1066,7 +1067,8 @@ build_column_default(Relation rel, int attrno)
 								 atttype, atttypmod,
 								 COERCION_ASSIGNMENT,
 								 COERCE_IMPLICIT_CAST,
-								 -1);
+								 -1,
+								 NameStr(att_tup->attname));
 	if (expr == NULL)
 		ereport(ERROR,
 				(errcode(ERRCODE_DATATYPE_MISMATCH),
@@ -1176,7 +1178,8 @@ rewriteValuesRTE(RangeTblEntry *rte, Relation target_relation, List *attrnos)
 												COERCE_IMPLICIT_CAST,
 												-1,
 												false,
-												false);
+												false,
+												NULL);
 				}
 				newList = lappend(newList, new_expr);
 			}
diff --git a/src/backend/rewrite/rewriteManip.c b/src/backend/rewrite/rewriteManip.c
index 1da90ff..eea17dd 100644
--- a/src/backend/rewrite/rewriteManip.c
+++ b/src/backend/rewrite/rewriteManip.c
@@ -1406,7 +1406,8 @@ ReplaceVarsFromTargetList_callback(Var *var,
 										COERCE_IMPLICIT_CAST,
 										-1,
 										false,
-										false);
+										false,
+										NULL);
 		}
 		elog(ERROR, "could not find replacement targetlist entry for attno %d",
 			 var->varattno);
diff --git a/src/backend/utils/adt/varchar.c b/src/backend/utils/adt/varchar.c
index df9a2d7..1a9eec4 100644
--- a/src/backend/utils/adt/varchar.c
+++ b/src/backend/utils/adt/varchar.c
@@ -267,6 +267,7 @@ bpchar(PG_FUNCTION_ARGS)
 	BpChar	   *source = PG_GETARG_BPCHAR_PP(0);
 	int32		maxlen = PG_GETARG_INT32(1);
 	bool		isExplicit = PG_GETARG_BOOL(2);
+	char		*colname = PG_GETARG_CSTRING(3);
 	BpChar	   *result;
 	int32		len;
 	char	   *r;
@@ -303,7 +304,8 @@ bpchar(PG_FUNCTION_ARGS)
 				if (s[i] != ' ')
 					ereport(ERROR,
 							(errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION),
-							 errmsg("value too long for type character(%d)",
+							 errmsg("value too long for %s of type character(%d)",
+									colname,
 									maxlen)));
 		}
 
@@ -594,6 +596,7 @@ varchar(PG_FUNCTION_ARGS)
 	VarChar    *source = PG_GETARG_VARCHAR_PP(0);
 	int32		typmod = PG_GETARG_INT32(1);
 	bool		isExplicit = PG_GETARG_BOOL(2);
+	char		*colname = PG_GETARG_CSTRING(3);
 	int32		len,
 				maxlen;
 	size_t		maxmblen;
@@ -619,7 +622,8 @@ varchar(PG_FUNCTION_ARGS)
 			if (s_data[i] != ' ')
 				ereport(ERROR,
 						(errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION),
-					  errmsg("value too long for type character varying(%d)",
+					  errmsg("value too long for %s of type character varying(%d)",
+							 colname ? colname : "(unknown column)",
 							 maxlen)));
 	}
 
diff --git a/src/include/parser/parse_coerce.h b/src/include/parser/parse_coerce.h
index ec0ee14..cb131ce 100644
--- a/src/include/parser/parse_coerce.h
+++ b/src/include/parser/parse_coerce.h
@@ -40,17 +40,18 @@ extern Node *coerce_to_target_type(ParseState *pstate,
 					  Oid targettype, int32 targettypmod,
 					  CoercionContext ccontext,
 					  CoercionForm cformat,
-					  int location);
+					  int location,
+					  char *colname);
 extern bool can_coerce_type(int nargs, Oid *input_typeids, Oid *target_typeids,
 				CoercionContext ccontext);
 extern Node *coerce_type(ParseState *pstate, Node *node,
 			Oid inputTypeId, Oid targetTypeId, int32 targetTypeMod,
-			CoercionContext ccontext, CoercionForm cformat, int location);
+			CoercionContext ccontext, CoercionForm cformat, int location, char *colname);
 extern Node *coerce_to_domain(Node *arg, Oid baseTypeId, int32 baseTypeMod,
 				 Oid typeId,
 				 CoercionForm cformat, int location,
 				 bool hideInputCoercion,
-				 bool lengthCoercionDone);
+				 bool lengthCoercionDone, char *colname);
 
 extern Node *coerce_to_boolean(ParseState *pstate, Node *node,
 				  const char *constructName);
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index aac7cda..9677887 100644
--- a/src/pl/plpgsql/src/pl_exec.c
+++ b/src/pl/plpgsql/src/pl_exec.c
@@ -6022,7 +6022,8 @@ get_cast_expression(PLpgSQL_execstate *estate,
 										  dsttype, dsttypmod,
 										  COERCION_ASSIGNMENT,
 										  COERCE_IMPLICIT_CAST,
-										  -1);
+										  -1,
+										  NULL);
 
 	/*
 	 * If there's no cast path according to the parser, fall back to using an
@@ -6046,7 +6047,8 @@ get_cast_expression(PLpgSQL_execstate *estate,
 											  dsttype, dsttypmod,
 											  COERCION_ASSIGNMENT,
 											  COERCE_IMPLICIT_CAST,
-											  -1);
+											  -1,
+											  NULL);
 	}
 
 	/* Note: we don't bother labeling the expression tree with collation */
