diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index 4e0492b..ddaf900 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -4183,6 +4183,16 @@ CREATE TABLE postgres_log
   query_pos integer,
   location text,
   application_name text,
+  column_name text,
+  table_name text,
+  schema_name text,
+  constraint_name text,
+  constraint_table text,
+  constraint_schema text,
+  routine_name text,
+  trigger_name text,
+  trigger_table text,
+  trigger_schema text,
   PRIMARY KEY (session_id, session_line_num)
 );
 </programlisting>
diff --git a/doc/src/sgml/protocol.sgml b/doc/src/sgml/protocol.sgml
index e725563..6f34448 100644
--- a/doc/src/sgml/protocol.sgml
+++ b/doc/src/sgml/protocol.sgml
@@ -4720,6 +4720,127 @@ message.
 </listitem>
 </varlistentry>
 
+<varlistentry>
+<term>
+<literal>c</>
+</term>
+<listitem>
+<para>
+        Column name: the name of column related to error
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<literal>t</>
+</term>
+<listitem>
+<para>
+        Table name: the name of table related to error
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<literal>s</>
+</term>
+<listitem>
+<para>
+        Schema name: the name of schema related to error
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<literal>n</>
+</term>
+<listitem>
+<para>
+        Constraint name: the name of constraint related to error
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<literal>o</>
+</term>
+<listitem>
+<para>
+        Constraint table: the table name of constraint related to error
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<literal>m</>
+</term>
+<listitem>
+<para>
+        Constraint schema: the schema of constraint related to error
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<literal>r</>
+</term>
+<listitem>
+<para>
+        Routine name: the name of routine related to error
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<literal>u</>
+</term>
+<listitem>
+<para>
+        Routine schema: the schema of routine related to error
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<literal>g</>
+</term>
+<listitem>
+<para>
+        Trigger name: the name of trigger related to error
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<literal>i</>
+</term>
+<listitem>
+<para>
+        Trigger table: the table of trigger related to error
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<literal>h</>
+</term>
+<listitem>
+<para>
+        Trigger schema: the schema of trigger related to error
+</para>
+</listitem>
+</varlistentry>
+
 </variablelist>
 
 <para>
diff --git a/src/backend/access/nbtree/nbtinsert.c b/src/backend/access/nbtree/nbtinsert.c
index 3ed9b5c..419823c 100644
--- a/src/backend/access/nbtree/nbtinsert.c
+++ b/src/backend/access/nbtree/nbtinsert.c
@@ -23,6 +23,7 @@
 #include "storage/predicate.h"
 #include "utils/inval.h"
 #include "utils/tqual.h"
+#include "utils/relerror.h"
 
 
 typedef struct
@@ -393,7 +394,8 @@ _bt_check_unique(Relation rel, IndexTuple itup, Relation heapRel,
 										RelationGetRelationName(rel)),
 								 errdetail("Key %s already exists.",
 										   BuildIndexValueDescription(rel,
-														  values, isnull))));
+														  values, isnull)),
+								 errrelation(rel)));
 					}
 				}
 				else if (all_dead)
@@ -455,7 +457,8 @@ _bt_check_unique(Relation rel, IndexTuple itup, Relation heapRel,
 				(errcode(ERRCODE_INTERNAL_ERROR),
 				 errmsg("failed to re-find tuple within index \"%s\"",
 						RelationGetRelationName(rel)),
-		errhint("This may be because of a non-immutable index expression.")));
+		errhint("This may be because of a non-immutable index expression."),
+				 errrelation(rel)));
 
 	if (nbuf != InvalidBuffer)
 		_bt_relbuf(rel, nbuf);
@@ -533,7 +536,8 @@ _bt_findinsertloc(Relation rel,
 				   RelationGetRelationName(rel)),
 		errhint("Values larger than 1/3 of a buffer page cannot be indexed.\n"
 				"Consider a function index of an MD5 hash of the value, "
-				"or use full text indexing.")));
+				"or use full text indexing."),
+				errrelation(rel)));
 
 	/*----------
 	 * If we will need to split the page to put the item on this page,
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index d69809a..91b8665 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -81,6 +81,7 @@
 #include "utils/lsyscache.h"
 #include "utils/memutils.h"
 #include "utils/relcache.h"
+#include "utils/relerror.h"
 #include "utils/snapmgr.h"
 #include "utils/syscache.h"
 #include "utils/tqual.h"
@@ -3808,6 +3809,10 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
 					ereport(ERROR,
 							(errcode(ERRCODE_NOT_NULL_VIOLATION),
 							 errmsg("column \"%s\" contains null values",
+								NameStr(newTupDesc->attrs[attn]->attname)),
+							 (newrel) ? errrelation_column(newrel,
+								NameStr(newTupDesc->attrs[attn]->attname)) :
+							errrelation_column(oldrel,
 								NameStr(newTupDesc->attrs[attn]->attname))));
 			}
 
@@ -3822,7 +3827,9 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
 							ereport(ERROR,
 									(errcode(ERRCODE_CHECK_VIOLATION),
 									 errmsg("check constraint \"%s\" is violated by some row",
-											con->name)));
+											con->name),
+						 (newrel) ? errrelation(newrel) : errrelation(oldrel),
+						 (newrel) ? errconstraint(newrel, con->name) : errconstraint(oldrel, con->name)));
 						break;
 					case CONSTR_FOREIGN:
 						/* Nothing to do here */
@@ -6632,7 +6639,9 @@ validateCheckConstraint(Relation rel, HeapTuple constrtup)
 			ereport(ERROR,
 					(errcode(ERRCODE_CHECK_VIOLATION),
 					 errmsg("check constraint \"%s\" is violated by some row",
-							NameStr(constrForm->conname))));
+							NameStr(constrForm->conname)),
+					 errrelation(rel),
+					 errconstraint(rel, NameStr(constrForm->conname))));
 
 		ResetExprContext(econtext);
 	}
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index 30850b2..040adab 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -69,6 +69,7 @@
 #include "utils/lsyscache.h"
 #include "utils/memutils.h"
 #include "utils/rel.h"
+#include "utils/relerror.h"
 #include "utils/syscache.h"
 #include "utils/tqual.h"
 
@@ -2233,7 +2234,9 @@ AlterDomainNotNull(List *names, bool notNull)
 								(errcode(ERRCODE_NOT_NULL_VIOLATION),
 								 errmsg("column \"%s\" of table \"%s\" contains null values",
 								NameStr(tupdesc->attrs[attnum - 1]->attname),
-										RelationGetRelationName(testrel))));
+										RelationGetRelationName(testrel)),
+								 errrelation_column(testrel,
+								NameStr(tupdesc->attrs[attnum - 1]->attname))));
 				}
 			}
 			heap_endscan(scan);
@@ -2602,7 +2605,9 @@ validateDomainConstraint(Oid domainoid, char *ccbin)
 							(errcode(ERRCODE_CHECK_VIOLATION),
 							 errmsg("column \"%s\" of table \"%s\" contains values that violate the new constraint",
 								NameStr(tupdesc->attrs[attnum - 1]->attname),
-									RelationGetRelationName(testrel))));
+									RelationGetRelationName(testrel)),
+							errrelation_column(testrel,
+								NameStr(tupdesc->attrs[attnum - 1]->attname))));
 			}
 
 			ResetExprContext(econtext);
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index 440438b..8332ecf 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -53,6 +53,7 @@
 #include "utils/acl.h"
 #include "utils/lsyscache.h"
 #include "utils/memutils.h"
+#include "utils/relerror.h"
 #include "utils/snapmgr.h"
 #include "utils/tqual.h"
 
@@ -1522,7 +1523,9 @@ ExecConstraints(ResultRelInfo *resultRelInfo,
 						 errmsg("null value in column \"%s\" violates not-null constraint",
 						  NameStr(rel->rd_att->attrs[attrChk - 1]->attname)),
 						 errdetail("Failing row contains %s.",
-								   ExecBuildSlotValueDescription(slot, 64))));
+								   ExecBuildSlotValueDescription(slot, 64)),
+						 errrelation_column(rel,
+							   NameStr(rel->rd_att->attrs[attrChk - 1]->attname))));
 		}
 	}
 
@@ -1536,7 +1539,9 @@ ExecConstraints(ResultRelInfo *resultRelInfo,
 					 errmsg("new row for relation \"%s\" violates check constraint \"%s\"",
 							RelationGetRelationName(rel), failed),
 					 errdetail("Failing row contains %s.",
-							   ExecBuildSlotValueDescription(slot, 64))));
+							   ExecBuildSlotValueDescription(slot, 64)),
+					 errrelation(rel),
+					 errconstraint(rel, failed)));
 	}
 }
 
diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c
index 2bd8b42..7f0d331 100644
--- a/src/backend/executor/execUtils.c
+++ b/src/backend/executor/execUtils.c
@@ -50,6 +50,7 @@
 #include "parser/parsetree.h"
 #include "storage/lmgr.h"
 #include "utils/memutils.h"
+#include "utils/relerror.h"
 #include "utils/tqual.h"
 
 
@@ -1304,14 +1305,16 @@ retry:
 					 errmsg("could not create exclusion constraint \"%s\"",
 							RelationGetRelationName(index)),
 					 errdetail("Key %s conflicts with key %s.",
-							   error_new, error_existing)));
+							   error_new, error_existing),
+					 errrelation(index)));
 		else
 			ereport(ERROR,
 					(errcode(ERRCODE_EXCLUSION_VIOLATION),
 					 errmsg("conflicting key value violates exclusion constraint \"%s\"",
 							RelationGetRelationName(index)),
 					 errdetail("Key %s conflicts with existing key %s.",
-							   error_new, error_existing)));
+							   error_new, error_existing),
+					 errrelation(index)));
 	}
 
 	index_endscan(index_scan);
diff --git a/src/backend/utils/adt/ri_triggers.c b/src/backend/utils/adt/ri_triggers.c
index 983f631..48b02d5 100644
--- a/src/backend/utils/adt/ri_triggers.c
+++ b/src/backend/utils/adt/ri_triggers.c
@@ -49,6 +49,7 @@
 #include "utils/lsyscache.h"
 #include "utils/memutils.h"
 #include "utils/rel.h"
+#include "utils/relerror.h"
 #include "utils/snapmgr.h"
 #include "utils/syscache.h"
 #include "utils/tqual.h"
@@ -338,7 +339,9 @@ RI_FKey_check(TriggerData *trigdata)
 							 errmsg("insert or update on table \"%s\" violates foreign key constraint \"%s\"",
 							  RelationGetRelationName(trigdata->tg_relation),
 									NameStr(riinfo->conname)),
-							 errdetail("MATCH FULL does not allow mixing of null and nonnull key values.")));
+							 errdetail("MATCH FULL does not allow mixing of null and nonnull key values."),
+							 errrelation(trigdata->tg_relation),
+						   errconstraint(trigdata->tg_relation, NameStr(riinfo->conname))));
 					heap_close(pk_rel, RowShareLock);
 					return PointerGetDatum(NULL);
 
@@ -2466,7 +2469,10 @@ RI_Initial_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel)
 					 errmsg("insert or update on table \"%s\" violates foreign key constraint \"%s\"",
 							RelationGetRelationName(fk_rel),
 							NameStr(fake_riinfo.conname)),
-					 errdetail("MATCH FULL does not allow mixing of null and nonnull key values.")));
+					 errdetail("match full does not allow mixing of null and nonnull key values."),
+					 errrelation(fk_rel),
+					 errconstraint(fk_rel, NameStr(fake_riinfo.conname))));
+
 
 		/*
 		 * We tell ri_ReportViolation we were doing the RI_PLAN_CHECK_LOOKUPPK
@@ -3218,7 +3224,9 @@ ri_ReportViolation(const RI_ConstraintInfo *riinfo,
 						NameStr(riinfo->conname)),
 				 errdetail("Key (%s)=(%s) is not present in table \"%s\".",
 						   key_names.data, key_values.data,
-						   RelationGetRelationName(pk_rel))));
+						   RelationGetRelationName(pk_rel)),
+				 errrelation(fk_rel),
+				 errconstraint(fk_rel, NameStr(riinfo->conname))));
 	else
 		ereport(ERROR,
 				(errcode(ERRCODE_FOREIGN_KEY_VIOLATION),
@@ -3228,7 +3236,9 @@ ri_ReportViolation(const RI_ConstraintInfo *riinfo,
 						RelationGetRelationName(fk_rel)),
 			errdetail("Key (%s)=(%s) is still referenced from table \"%s\".",
 					  key_names.data, key_values.data,
-					  RelationGetRelationName(fk_rel))));
+					  RelationGetRelationName(fk_rel)),
+				 errrelation(pk_rel),
+				 errconstraint(fk_rel, NameStr(riinfo->conname))));
 }
 
 
diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c
index a40b343..93f39eb 100644
--- a/src/backend/utils/error/elog.c
+++ b/src/backend/utils/error/elog.c
@@ -75,9 +75,11 @@
 #include "storage/proc.h"
 #include "tcop/tcopprot.h"
 #include "utils/guc.h"
+#include "utils/lsyscache.h"
 #include "utils/memutils.h"
 #include "utils/ps_status.h"
-
+#include "utils/rel.h"
+#include "utils/relerror.h"
 
 #undef _
 #define _(x) err_gettext(x)
@@ -477,6 +479,28 @@ errfinish(int dummy,...)
 		pfree(edata->context);
 	if (edata->internalquery)
 		pfree(edata->internalquery);
+	if (edata->column_name)
+		pfree(edata->column_name);
+	if (edata->table_name)
+		pfree(edata->table_name);
+	if (edata->schema_name)
+		pfree(edata->schema_name);
+	if (edata->constraint_name)
+		pfree(edata->constraint_name);
+	if (edata->constraint_table)
+		pfree(edata->constraint_table);
+	if (edata->constraint_schema)
+		pfree(edata->constraint_schema);
+	if (edata->routine_name)
+		pfree(edata->routine_name);
+	if (edata->routine_schema)
+		pfree(edata->routine_schema);
+	if (edata->trigger_name)
+		pfree(edata->trigger_name);
+	if (edata->trigger_table)
+		pfree(edata->trigger_table);
+	if (edata->trigger_schema)
+		pfree(edata->trigger_schema);
 
 	errordata_stack_depth--;
 
@@ -1079,6 +1103,157 @@ internalerrquery(const char *query)
 }
 
 /*
+ * Sets column_name, table_name and schema_name in ErrorData related to relation
+ */
+int
+errrelation_column(Relation rel, const char *colname)
+{
+	erritem(PG_DIAG_COLUMN_NAME, colname);
+	erritem(PG_DIAG_TABLE_NAME, RelationGetRelationName(rel));
+	erritem(PG_DIAG_SCHEMA_NAME,
+			get_namespace_name(RelationGetNamespace(rel)));
+
+	return 0;
+}
+
+/*
+ * Sets column_name, table_name and schema_name in ErrorData related to relation
+ */
+int
+errrelation(Relation rel)
+{
+	erritem(PG_DIAG_TABLE_NAME, RelationGetRelationName(rel));
+	erritem(PG_DIAG_SCHEMA_NAME,
+			get_namespace_name(RelationGetNamespace(rel)));
+
+	return 0;
+}
+
+/*
+ * Sets constraint_name, constraint_table  and constraint_schema in ErrorData
+ */
+int
+errconstraint(Relation rel, const char *cname)
+{
+	erritem(PG_DIAG_CONSTRAINT_NAME, cname);
+	erritem(PG_DIAG_CONSTRAINT_TABLE, RelationGetRelationName(rel));
+	erritem(PG_DIAG_CONSTRAINT_SCHEMA,
+			get_namespace_name(RelationGetNamespace(rel)));
+
+	return 0;
+}
+
+/*
+ * set ErrorData field - ensure not overwriting for selected fields
+ */
+static void
+set_field(char **ptr, const char *str, bool overwrite)
+{
+	if (*ptr != NULL)
+	{
+		/*
+		 * for some cases like ROUTINE_NAME, ROUTINE_SCHEMA we would
+		 * to get the most older value.
+		 */
+		if (!overwrite)
+			return;
+
+		pfree(*ptr);
+		*ptr = NULL;
+	}
+
+	if (str != NULL)
+		*ptr = MemoryContextStrdup(ErrorContext, str);
+}
+
+/*
+ * erritem -- generic setting of ErrorData string fields
+ */
+int
+erritem(int field, const char *str)
+{
+	ErrorData  *edata = &errordata[errordata_stack_depth];
+
+	/* we don't bother incrementing recursion_depth */
+	CHECK_STACK_DEPTH();
+
+	switch (field)
+	{
+		case PG_DIAG_MESSAGE_PRIMARY:
+			set_field(&edata->message, str, true);
+			break;
+
+		case PG_DIAG_MESSAGE_DETAIL:
+			set_field(&edata->detail, str, true);
+			break;
+
+		case PG_DIAG_MESSAGE_HINT:
+			set_field(&edata->hint, str, true);
+			break;
+
+		case PG_DIAG_CONTEXT:
+			set_field(&edata->context, str, true);
+			break;
+
+		case PG_DIAG_COLUMN_NAME:
+			set_field(&edata->column_name, str, true);
+			break;
+
+		case PG_DIAG_TABLE_NAME:
+			set_field(&edata->table_name, str, true);
+			break;
+
+		case PG_DIAG_SCHEMA_NAME:
+			set_field(&edata->schema_name, str, true);
+			break;
+
+		case PG_DIAG_CONSTRAINT_NAME:
+			set_field(&edata->constraint_name, str, true);
+			break;
+
+		case PG_DIAG_CONSTRAINT_TABLE:
+			set_field(&edata->constraint_table, str, true);
+			break;
+
+		case PG_DIAG_CONSTRAINT_SCHEMA:
+			set_field(&edata->constraint_schema, str, true);
+			break;
+
+		/*
+		 * setup of routine_name, routine_schema, trigger_name,
+		 * trigger_table, trigger_schema is processed together
+		 * with collecting context. Only first values are valid,
+		 * so we should to protect these values.
+		 */
+		case PG_DIAG_ROUTINE_NAME:
+			set_field(&edata->routine_name, str, false);
+			break;
+
+		case PG_DIAG_ROUTINE_SCHEMA:
+			set_field(&edata->routine_schema, str, false);
+			break;
+
+		case PG_DIAG_TRIGGER_NAME:
+			set_field(&edata->trigger_name, str, false);
+			break;
+
+		case PG_DIAG_TRIGGER_TABLE:
+			set_field(&edata->trigger_table, str, false);
+			break;
+
+		case PG_DIAG_TRIGGER_SCHEMA:
+			set_field(&edata->trigger_schema, str, false);
+			break;
+
+		default:
+			elog(ERROR, "unknown ErrorData field id %d",
+						    field);
+	}
+
+	return 0;			/* return value does not matter */
+}
+
+/*
  * geterrcode --- return the currently set SQLSTATE error code
  *
  * This is only intended for use in error callback subroutines, since there
@@ -1352,6 +1527,28 @@ CopyErrorData(void)
 		newedata->context = pstrdup(newedata->context);
 	if (newedata->internalquery)
 		newedata->internalquery = pstrdup(newedata->internalquery);
+	if (newedata->column_name)
+		newedata->column_name = pstrdup(newedata->column_name);
+	if (newedata->table_name)
+		newedata->table_name = pstrdup(newedata->table_name);
+	if (newedata->schema_name)
+		newedata->schema_name = pstrdup(newedata->schema_name);
+	if (newedata->constraint_name)
+		newedata->constraint_name = pstrdup(newedata->constraint_name);
+	if (newedata->constraint_table)
+		newedata->constraint_table = pstrdup(newedata->constraint_table);
+	if (newedata->constraint_schema)
+		newedata->constraint_schema = pstrdup(newedata->constraint_schema);
+	if (newedata->routine_name)
+		newedata->routine_name = pstrdup(newedata->routine_name);
+	if (newedata->routine_schema)
+		newedata->routine_schema = pstrdup(newedata->routine_schema);
+	if (newedata->trigger_name)
+		newedata->trigger_name = pstrdup(newedata->trigger_name);
+	if (newedata->trigger_table)
+		newedata->trigger_table = pstrdup(newedata->trigger_table);
+	if (newedata->trigger_schema)
+		newedata->trigger_schema = pstrdup(newedata->trigger_schema);
 
 	return newedata;
 }
@@ -1377,6 +1574,28 @@ FreeErrorData(ErrorData *edata)
 		pfree(edata->context);
 	if (edata->internalquery)
 		pfree(edata->internalquery);
+	if (edata->column_name)
+		pfree(edata->column_name);
+	if (edata->table_name)
+		pfree(edata->table_name);
+	if (edata->schema_name)
+		pfree(edata->schema_name);
+	if (edata->constraint_name)
+		pfree(edata->constraint_name);
+	if (edata->constraint_table)
+		pfree(edata->constraint_table);
+	if (edata->constraint_schema)
+		pfree(edata->constraint_schema);
+	if (edata->routine_name)
+		pfree(edata->routine_name);
+	if (edata->routine_schema)
+		pfree(edata->routine_schema);
+	if (edata->trigger_name)
+		pfree(edata->trigger_name);
+	if (edata->trigger_table)
+		pfree(edata->trigger_table);
+	if (edata->trigger_schema)
+		pfree(edata->trigger_schema);
 	pfree(edata);
 }
 
@@ -1449,6 +1668,28 @@ ReThrowError(ErrorData *edata)
 		newedata->context = pstrdup(newedata->context);
 	if (newedata->internalquery)
 		newedata->internalquery = pstrdup(newedata->internalquery);
+	if (newedata->column_name)
+		newedata->column_name = pstrdup(newedata->column_name);
+	if (newedata->table_name)
+		newedata->table_name = pstrdup(newedata->table_name);
+	if (newedata->schema_name)
+		newedata->schema_name = pstrdup(newedata->schema_name);
+	if (newedata->constraint_name)
+		newedata->constraint_name = pstrdup(newedata->constraint_name);
+	if (newedata->constraint_table)
+		newedata->constraint_table = pstrdup(newedata->constraint_table);
+	if (newedata->constraint_schema)
+		newedata->constraint_schema = pstrdup(newedata->constraint_schema);
+	if (newedata->routine_name)
+		newedata->routine_name = pstrdup(newedata->routine_name);
+	if (newedata->routine_schema)
+		newedata->routine_schema = pstrdup(newedata->routine_schema);
+	if (newedata->trigger_name)
+		newedata->trigger_name = pstrdup(newedata->trigger_name);
+	if (newedata->trigger_table)
+		newedata->trigger_table = pstrdup(newedata->trigger_table);
+	if (newedata->trigger_schema)
+		newedata->trigger_schema = pstrdup(newedata->trigger_schema);
 
 	recursion_depth--;
 	PG_RE_THROW();
@@ -2259,6 +2500,39 @@ write_csvlog(ErrorData *edata)
 	/* application name */
 	if (application_name)
 		appendCSVLiteral(&buf, application_name);
+	appendStringInfoChar(&buf, ',');
+
+	appendCSVLiteral(&buf, edata->column_name);
+	appendStringInfoChar(&buf, ',');
+
+	appendCSVLiteral(&buf, edata->table_name);
+	appendStringInfoChar(&buf, ',');
+
+	appendCSVLiteral(&buf, edata->schema_name);
+	appendStringInfoChar(&buf, ',');
+
+	appendCSVLiteral(&buf, edata->constraint_name);
+	appendStringInfoChar(&buf, ',');
+
+	appendCSVLiteral(&buf, edata->constraint_table);
+	appendStringInfoChar(&buf, ',');
+
+	appendCSVLiteral(&buf, edata->constraint_schema);
+	appendStringInfoChar(&buf, ',');
+
+	appendCSVLiteral(&buf, edata->routine_name);
+	appendStringInfoChar(&buf, ',');
+
+	appendCSVLiteral(&buf, edata->routine_schema);
+	appendStringInfoChar(&buf, ',');
+
+	appendCSVLiteral(&buf, edata->trigger_name);
+	appendStringInfoChar(&buf, ',');
+
+	appendCSVLiteral(&buf, edata->trigger_table);
+	appendStringInfoChar(&buf, ',');
+
+	appendCSVLiteral(&buf, edata->trigger_schema);
 
 	appendStringInfoChar(&buf, '\n');
 
@@ -2377,6 +2651,83 @@ send_message_to_server_log(ErrorData *edata)
 				appendStringInfo(&buf, _("LOCATION:  %s:%d\n"),
 								 edata->filename, edata->lineno);
 			}
+			if (edata->column_name)
+			{
+				log_line_prefix(&buf, edata);
+				appendStringInfoString(&buf, _("COLUMN NAME:  "));
+				append_with_tabs(&buf, edata->column_name);
+				appendStringInfoChar(&buf, '\n');
+			}
+			if (edata->table_name)
+			{
+				log_line_prefix(&buf, edata);
+				appendStringInfoString(&buf, _("TABLE NAME:  "));
+				append_with_tabs(&buf, edata->table_name);
+				appendStringInfoChar(&buf, '\n');
+			}
+			if (edata->schema_name)
+			{
+				log_line_prefix(&buf, edata);
+				appendStringInfoString(&buf, _("SCHEMA NAME:  "));
+				append_with_tabs(&buf, edata->schema_name);
+				appendStringInfoChar(&buf, '\n');
+			}
+			if (edata->constraint_name)
+			{
+				log_line_prefix(&buf, edata);
+				appendStringInfoString(&buf, _("CONSTRAINT NAME:  "));
+				append_with_tabs(&buf, edata->constraint_name);
+				appendStringInfoChar(&buf, '\n');
+			}
+			if (edata->constraint_table)
+			{
+				log_line_prefix(&buf, edata);
+				appendStringInfoString(&buf, _("CONSTRAINT TABLE:  "));
+				append_with_tabs(&buf, edata->constraint_table);
+				appendStringInfoChar(&buf, '\n');
+			}
+			if (edata->constraint_schema)
+			{
+				log_line_prefix(&buf, edata);
+				appendStringInfoString(&buf, _("CONSTRAINT SCHEMA:  "));
+				append_with_tabs(&buf, edata->constraint_schema);
+				appendStringInfoChar(&buf, '\n');
+			}
+			if (edata->routine_name)
+			{
+				log_line_prefix(&buf, edata);
+				appendStringInfoString(&buf, _("ROUTINE NAME:  "));
+				append_with_tabs(&buf, edata->routine_name);
+				appendStringInfoChar(&buf, '\n');
+			}
+			if (edata->routine_schema)
+			{
+				log_line_prefix(&buf, edata);
+				appendStringInfoString(&buf, _("ROUTINE SCHEMA:  "));
+				append_with_tabs(&buf, edata->routine_schema);
+				appendStringInfoChar(&buf, '\n');
+			}
+			if (edata->trigger_name)
+			{
+				log_line_prefix(&buf, edata);
+				appendStringInfoString(&buf, _("TRIGGER NAME:  "));
+				append_with_tabs(&buf, edata->trigger_name);
+				appendStringInfoChar(&buf, '\n');
+			}
+			if (edata->trigger_table)
+			{
+				log_line_prefix(&buf, edata);
+				appendStringInfoString(&buf, _("TRIGGER TABLE:  "));
+				append_with_tabs(&buf, edata->trigger_table);
+				appendStringInfoChar(&buf, '\n');
+			}
+			if (edata->trigger_schema)
+			{
+				log_line_prefix(&buf, edata);
+				appendStringInfoString(&buf, _("TRIGGER SCHEMA:  "));
+				append_with_tabs(&buf, edata->trigger_schema);
+				appendStringInfoChar(&buf, '\n');
+			}
 		}
 	}
 
@@ -2673,6 +3024,72 @@ send_message_to_frontend(ErrorData *edata)
 			err_sendstring(&msgbuf, edata->funcname);
 		}
 
+		if (edata->column_name)
+		{
+			pq_sendbyte(&msgbuf, PG_DIAG_COLUMN_NAME);
+			err_sendstring(&msgbuf, edata->column_name);
+		}
+
+		if (edata->table_name)
+		{
+			pq_sendbyte(&msgbuf, PG_DIAG_TABLE_NAME);
+			err_sendstring(&msgbuf, edata->table_name);
+		}
+
+		if (edata->schema_name)
+		{
+			pq_sendbyte(&msgbuf, PG_DIAG_SCHEMA_NAME);
+			err_sendstring(&msgbuf, edata->schema_name);
+		}
+
+		if (edata->constraint_name)
+		{
+			pq_sendbyte(&msgbuf, PG_DIAG_CONSTRAINT_NAME);
+			err_sendstring(&msgbuf, edata->constraint_name);
+		}
+
+		if (edata->constraint_table)
+		{
+			pq_sendbyte(&msgbuf, PG_DIAG_CONSTRAINT_TABLE);
+			err_sendstring(&msgbuf, edata->constraint_table);
+		}
+
+		if (edata->constraint_schema)
+		{
+			pq_sendbyte(&msgbuf, PG_DIAG_CONSTRAINT_SCHEMA);
+			err_sendstring(&msgbuf, edata->constraint_schema);
+		}
+
+		if (edata->routine_name)
+		{
+			pq_sendbyte(&msgbuf, PG_DIAG_ROUTINE_NAME);
+			err_sendstring(&msgbuf, edata->routine_name);
+		}
+
+		if (edata->routine_schema)
+		{
+			pq_sendbyte(&msgbuf, PG_DIAG_ROUTINE_SCHEMA);
+			err_sendstring(&msgbuf, edata->routine_schema);
+		}
+
+		if (edata->trigger_name)
+		{
+			pq_sendbyte(&msgbuf, PG_DIAG_TRIGGER_NAME);
+			err_sendstring(&msgbuf, edata->trigger_name);
+		}
+
+		if (edata->trigger_table)
+		{
+			pq_sendbyte(&msgbuf, PG_DIAG_TRIGGER_TABLE);
+			err_sendstring(&msgbuf, edata->trigger_table);
+		}
+
+		if (edata->trigger_schema)
+		{
+			pq_sendbyte(&msgbuf, PG_DIAG_TRIGGER_SCHEMA);
+			err_sendstring(&msgbuf, edata->trigger_schema);
+		}
+
 		pq_sendbyte(&msgbuf, '\0');		/* terminator */
 	}
 	else
diff --git a/src/backend/utils/sort/tuplesort.c b/src/backend/utils/sort/tuplesort.c
index d5a2003..3a3c663 100644
--- a/src/backend/utils/sort/tuplesort.c
+++ b/src/backend/utils/sort/tuplesort.c
@@ -112,6 +112,7 @@
 #include "utils/memutils.h"
 #include "utils/pg_rusage.h"
 #include "utils/rel.h"
+#include "utils/relerror.h"
 #include "utils/sortsupport.h"
 #include "utils/tuplesort.h"
 
@@ -3090,7 +3091,8 @@ comparetup_index_btree(const SortTuple *a, const SortTuple *b,
 						RelationGetRelationName(state->indexRel)),
 				 errdetail("Key %s is duplicated.",
 						   BuildIndexValueDescription(state->indexRel,
-													  values, isnull))));
+													  values, isnull)),
+				 errrelation(state->indexRel)));
 	}
 
 	/*
diff --git a/src/include/postgres_ext.h b/src/include/postgres_ext.h
index b6ebb7a..829114a 100644
--- a/src/include/postgres_ext.h
+++ b/src/include/postgres_ext.h
@@ -55,5 +55,16 @@ typedef unsigned int Oid;
 #define PG_DIAG_SOURCE_FILE		'F'
 #define PG_DIAG_SOURCE_LINE		'L'
 #define PG_DIAG_SOURCE_FUNCTION 'R'
+#define PG_DIAG_COLUMN_NAME	'c'
+#define PG_DIAG_TABLE_NAME	't'
+#define PG_DIAG_SCHEMA_NAME	's'
+#define PG_DIAG_CONSTRAINT_NAME		'n'
+#define PG_DIAG_CONSTRAINT_TABLE	'o'
+#define PG_DIAG_CONSTRAINT_SCHEMA	'm'
+#define PG_DIAG_ROUTINE_NAME		'r'
+#define PG_DIAG_ROUTINE_SCHEMA		'u'
+#define PG_DIAG_TRIGGER_NAME		'g'
+#define PG_DIAG_TRIGGER_TABLE		'i'
+#define PG_DIAG_TRIGGER_SCHEMA		'h'
 
 #endif
diff --git a/src/include/utils/elog.h b/src/include/utils/elog.h
index 1bbfd2b..c897073 100644
--- a/src/include/utils/elog.h
+++ b/src/include/utils/elog.h
@@ -190,6 +190,8 @@ extern int	geterrcode(void);
 extern int	geterrposition(void);
 extern int	getinternalerrposition(void);
 
+extern int	erritem(int field, const char *str);
+
 
 /*----------
  * Old-style error reporting API: to be used in this way:
@@ -321,6 +323,17 @@ typedef struct ErrorData
 	char	   *detail_log;		/* detail error message for server log only */
 	char	   *hint;			/* hint message */
 	char	   *context;		/* context message */
+	char	   *column_name;		/* name of column */
+	char	   *table_name;			/* name of table */
+	char	   *schema_name;		/* name of schema */
+	char	   *constraint_name;		/* name of constraint */
+	char	   *constraint_table;		/* name of table related to constraint */
+	char	   *constraint_schema;		/* name of schema with constraint */
+	char	   *routine_name;		/* name of function that caused error */
+	char	   *routine_schema;		/* schema name of function that caused error */
+	char	   *trigger_name;		/* name of trigger that caused error */
+	char	   *trigger_table;		/* table of trigger that caused error */
+	char	   *trigger_schema;		/* schema of trigger that caused error */
 	int			cursorpos;		/* cursor index into query string */
 	int			internalpos;	/* cursor index into internalquery */
 	char	   *internalquery;	/* text of internally-generated query */
diff --git a/src/include/utils/relerror.h b/src/include/utils/relerror.h
new file mode 100644
index 0000000..357222e
--- /dev/null
+++ b/src/include/utils/relerror.h
@@ -0,0 +1,21 @@
+/*-------------------------------------------------------------------------
+ *
+ * relerror.h
+ *	  setting ErrorData fields related to Relation struct
+ *
+ * Copyright (c) 2007-2012, PostgreSQL Global Development Group
+ *
+ * src/include/utils/relerror.h
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef RELERROR_H
+#define RELERROR_H
+
+#include "utils/relcache.h"
+
+extern int errrelation_column(Relation rel, const char *colname);
+extern int errrelation(Relation rel);
+extern int errconstraint(Relation rel, const char *cname);
+
+#endif   /* RELERROR_H */
diff --git a/src/interfaces/libpq/fe-protocol3.c b/src/interfaces/libpq/fe-protocol3.c
index 173af2e..e83a8b7 100644
--- a/src/interfaces/libpq/fe-protocol3.c
+++ b/src/interfaces/libpq/fe-protocol3.c
@@ -980,6 +980,40 @@ pqGetErrorNotice3(PGconn *conn, bool isError)
 								  valf, vall);
 			appendPQExpBufferChar(&workBuf, '\n');
 		}
+
+		val = PQresultErrorField(res, PG_DIAG_COLUMN_NAME);
+		if (val)
+			appendPQExpBuffer(&workBuf, libpq_gettext("COLUMN NAME:  %s\n"), val);
+		val = PQresultErrorField(res, PG_DIAG_TABLE_NAME);
+		if (val)
+			appendPQExpBuffer(&workBuf, libpq_gettext("TABLE NAME:  %s\n"), val);
+		val = PQresultErrorField(res, PG_DIAG_SCHEMA_NAME);
+		if (val)
+			appendPQExpBuffer(&workBuf, libpq_gettext("SCHEMA NAME:  %s\n"), val);
+		val = PQresultErrorField(res, PG_DIAG_CONSTRAINT_NAME);
+		if (val)
+			appendPQExpBuffer(&workBuf, libpq_gettext("CONSTRAINT NAME:  %s\n"), val);
+		val = PQresultErrorField(res, PG_DIAG_CONSTRAINT_TABLE);
+		if (val)
+			appendPQExpBuffer(&workBuf, libpq_gettext("CONSTRAINT TABLE:  %s\n"), val);
+		val = PQresultErrorField(res, PG_DIAG_CONSTRAINT_SCHEMA);
+		if (val)
+			appendPQExpBuffer(&workBuf, libpq_gettext("CONSTRAINT SCHEMA:  %s\n"), val);
+		val = PQresultErrorField(res, PG_DIAG_ROUTINE_NAME);
+		if (val)
+			appendPQExpBuffer(&workBuf, libpq_gettext("ROUTINE NAME:  %s\n"), val);
+		val = PQresultErrorField(res, PG_DIAG_ROUTINE_SCHEMA);
+		if (val)
+			appendPQExpBuffer(&workBuf, libpq_gettext("ROUTINE SCHEMA:  %s\n"), val);
+		val = PQresultErrorField(res, PG_DIAG_TRIGGER_NAME);
+		if (val)
+			appendPQExpBuffer(&workBuf, libpq_gettext("TRIGGER NAME:  %s\n"), val);
+		val = PQresultErrorField(res, PG_DIAG_TRIGGER_TABLE);
+		if (val)
+			appendPQExpBuffer(&workBuf, libpq_gettext("TRIGGER TABLE:  %s\n"), val);
+		val = PQresultErrorField(res, PG_DIAG_TRIGGER_SCHEMA);
+		if (val)
+			appendPQExpBuffer(&workBuf, libpq_gettext("TRIGGER SCHEMA:  %s\n"), val);
 	}
 
 	/*
