diff doc/src/sgml/config.sgml
index 074afee..5cf2fe3
*** a/doc/src/sgml/config.sgml
--- b/doc/src/sgml/config.sgml
*************** CREATE TABLE postgres_log
*** 4180,4185 ****
--- 4180,4193 ----
    query_pos integer,
    location text,
    application_name text,
+   column_name text,
+   table_name text,
+   schema_name text,
+   constraint_name text,
+   constraint_schema text,
+   routine_name text,
+   trigger_name text,
+   trigger_schema text,
    PRIMARY KEY (session_id, session_line_num)
  );
  </programlisting>
diff doc/src/sgml/protocol.sgml
index e725563..739d1fe
*** a/doc/src/sgml/protocol.sgml
--- b/doc/src/sgml/protocol.sgml
*************** message.
*** 4720,4725 ****
--- 4720,4824 ----
  </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>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>h</>
+ </term>
+ <listitem>
+ <para>
+         Trigger schema: the schema of trigger related to error
+ </para>
+ </listitem>
+ </varlistentry>
+
  </variablelist>

  <para>
diff src/backend/access/nbtree/nbtinsert.c
index 3ed9b5c..a5e5d12
*** a/src/backend/access/nbtree/nbtinsert.c
--- b/src/backend/access/nbtree/nbtinsert.c
*************** _bt_check_unique(Relation rel, IndexTupl
*** 393,399 ****
  										RelationGetRelationName(rel)),
  								 errdetail("Key %s already exists.",
  										   BuildIndexValueDescription(rel,
! 														  values, isnull))));
  					}
  				}
  				else if (all_dead)
--- 393,400 ----
  										RelationGetRelationName(rel)),
  								 errdetail("Key %s already exists.",
  										   BuildIndexValueDescription(rel,
! 														  values, isnull)),
! 								 constraint_relation_error(rel)));
  					}
  				}
  				else if (all_dead)
*************** _bt_check_unique(Relation rel, IndexTupl
*** 455,461 ****
  				(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.")));

  	if (nbuf != InvalidBuffer)
  		_bt_relbuf(rel, nbuf);
--- 456,463 ----
  				(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."),
! 				 relation_error(rel)));

  	if (nbuf != InvalidBuffer)
  		_bt_relbuf(rel, nbuf);
*************** _bt_findinsertloc(Relation rel,
*** 533,539 ****
  				   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.")));

  	/*----------
  	 * If we will need to split the page to put the item on this page,
--- 535,542 ----
  				   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."),
! 				relation_error(rel)));

  	/*----------
  	 * If we will need to split the page to put the item on this page,
diff src/backend/executor/execMain.c
index 440438b..11da994
*** a/src/backend/executor/execMain.c
--- b/src/backend/executor/execMain.c
*************** ExecConstraints(ResultRelInfo *resultRel
*** 1522,1528 ****
  						 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))));
  		}
  	}

--- 1522,1530 ----
  						 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)),
! 						 relation_column_error(rel, NameStr(rel->rd_att->attrs[attrChk - 1]->attname)),
! 						 constraint_error(rel, "not_null_violation")));
  		}
  	}

*************** ExecConstraints(ResultRelInfo *resultRel
*** 1536,1542 ****
  					 errmsg("new row for relation \"%s\" violates check constraint \"%s\"",
  							RelationGetRelationName(rel), failed),
  					 errdetail("Failing row contains %s.",
! 							   ExecBuildSlotValueDescription(slot, 64))));
  	}
  }

--- 1538,1546 ----
  					 errmsg("new row for relation \"%s\" violates check constraint \"%s\"",
  							RelationGetRelationName(rel), failed),
  					 errdetail("Failing row contains %s.",
! 							   ExecBuildSlotValueDescription(slot, 64)),
! 					 relation_error(rel),
! 					 constraint_error(rel, failed)));
  	}
  }

diff src/backend/executor/execUtils.c
index 2bd8b42..d64c747
*** a/src/backend/executor/execUtils.c
--- b/src/backend/executor/execUtils.c
*************** retry:
*** 1304,1317 ****
  					 errmsg("could not create exclusion constraint \"%s\"",
  							RelationGetRelationName(index)),
  					 errdetail("Key %s conflicts with key %s.",
! 							   error_new, error_existing)));
  		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)));
  	}

  	index_endscan(index_scan);
--- 1304,1319 ----
  					 errmsg("could not create exclusion constraint \"%s\"",
  							RelationGetRelationName(index)),
  					 errdetail("Key %s conflicts with key %s.",
! 							   error_new, error_existing),
! 					 constraint_relation_error(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),
! 					 constraint_relation_error(index)));
  	}

  	index_endscan(index_scan);
diff src/backend/utils/adt/ri_triggers.c
index 983f631..49859a8
*** a/src/backend/utils/adt/ri_triggers.c
--- b/src/backend/utils/adt/ri_triggers.c
*************** RI_FKey_check(TriggerData *trigdata)
*** 338,344 ****
  							 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.")));
  					heap_close(pk_rel, RowShareLock);
  					return PointerGetDatum(NULL);

--- 338,346 ----
  							 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."),
! 							 relation_error(trigdata->tg_relation),
! 					 constraint_error(trigdata->tg_relation, NameStr(riinfo->conname))));
  					heap_close(pk_rel, RowShareLock);
  					return PointerGetDatum(NULL);

*************** RI_Initial_Check(Trigger *trigger, Relat
*** 2466,2472 ****
  					 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.")));

  		/*
  		 * We tell ri_ReportViolation we were doing the RI_PLAN_CHECK_LOOKUPPK
--- 2468,2477 ----
  					 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."),
! 					 relation_error(fk_rel),
! 					 constraint_error(fk_rel, NameStr(fake_riinfo.conname))));
!

  		/*
  		 * We tell ri_ReportViolation we were doing the RI_PLAN_CHECK_LOOKUPPK
*************** ri_ReportViolation(const RI_ConstraintIn
*** 3218,3224 ****
  						NameStr(riinfo->conname)),
  				 errdetail("Key (%s)=(%s) is not present in table \"%s\".",
  						   key_names.data, key_values.data,
! 						   RelationGetRelationName(pk_rel))));
  	else
  		ereport(ERROR,
  				(errcode(ERRCODE_FOREIGN_KEY_VIOLATION),
--- 3223,3231 ----
  						NameStr(riinfo->conname)),
  				 errdetail("Key (%s)=(%s) is not present in table \"%s\".",
  						   key_names.data, key_values.data,
! 						   RelationGetRelationName(pk_rel)),
! 				 relation_error(fk_rel),
! 				 constraint_error(fk_rel, NameStr(riinfo->conname))));
  	else
  		ereport(ERROR,
  				(errcode(ERRCODE_FOREIGN_KEY_VIOLATION),
*************** ri_ReportViolation(const RI_ConstraintIn
*** 3228,3234 ****
  						RelationGetRelationName(fk_rel)),
  			errdetail("Key (%s)=(%s) is still referenced from table \"%s\".",
  					  key_names.data, key_values.data,
! 					  RelationGetRelationName(fk_rel))));
  }


--- 3235,3243 ----
  						RelationGetRelationName(fk_rel)),
  			errdetail("Key (%s)=(%s) is still referenced from table \"%s\".",
  					  key_names.data, key_values.data,
! 					  RelationGetRelationName(fk_rel)),
! 				 relation_error(pk_rel),
! 				 constraint_error(fk_rel, NameStr(riinfo->conname))));
  }


diff src/backend/utils/cache/relcache.c
index 2e6776e..80561b7
*** a/src/backend/utils/cache/relcache.c
--- b/src/backend/utils/cache/relcache.c
*************** unlink_initfile(const char *initfilename
*** 4624,4626 ****
--- 4624,4674 ----
  			elog(LOG, "could not remove cache file \"%s\": %m", initfilename);
  	}
  }
+
+ /*
+  * Sets column_name, table_name and schema_name in ErrorData related to relation
+  */
+ inline int
+ relation_column_error(Relation rel, const char *colname)
+ {
+ 	if (colname != NULL)
+ 		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
+  */
+ inline int
+ relation_error(Relation rel)
+ {
+ 	erritem(PG_DIAG_TABLE_NAME, RelationGetRelationName(rel));
+ 	erritem(PG_DIAG_SCHEMA_NAME, get_namespace_name(RelationGetNamespace(rel)));
+
+ 	return 0;
+ }
+
+ /*
+  * Sets constraint_name and constraint_schema in ErrorData
+  */
+ inline int
+ constraint_error(Relation rel, const char *cname)
+ {
+ 	erritem(PG_DIAG_CONSTRAINT_NAME, cname);
+ 	erritem(PG_DIAG_CONSTRAINT_SCHEMA, get_namespace_name(RelationGetNamespace(rel)));
+
+ 	return 0;
+ }
+
+ inline int
+ constraint_relation_error(Relation rel)
+ {
+ 	erritem(PG_DIAG_CONSTRAINT_NAME, RelationGetRelationName(rel));
+ 	erritem(PG_DIAG_CONSTRAINT_SCHEMA, get_namespace_name(RelationGetNamespace(rel)));
+
+ 	return 0;
+ }
diff src/backend/utils/error/elog.c
index a40b343..7fd952f
*** a/src/backend/utils/error/elog.c
--- b/src/backend/utils/error/elog.c
*************** errfinish(int dummy,...)
*** 477,482 ****
--- 477,500 ----
  		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_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_schema)
+ 		pfree(edata->trigger_schema);

  	errordata_stack_depth--;

*************** internalerrquery(const char *query)
*** 1078,1083 ****
--- 1096,1193 ----
  	return 0;					/* return value does not matter */
  }

+ static inline 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_SCHEMA:
+ 			set_field(&edata->constraint_schema, str, true);
+ 			break;
+
+ 		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_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
   *
*************** CopyErrorData(void)
*** 1352,1357 ****
--- 1462,1485 ----
  		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_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_schema)
+ 		newedata->trigger_schema = pstrdup(newedata->trigger_schema);

  	return newedata;
  }
*************** FreeErrorData(ErrorData *edata)
*** 1377,1382 ****
--- 1505,1528 ----
  		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_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_schema)
+ 		pfree(edata->trigger_schema);
  	pfree(edata);
  }

*************** ReThrowError(ErrorData *edata)
*** 1449,1454 ****
--- 1595,1618 ----
  		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_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_schema)
+ 		newedata->trigger_schema = pstrdup(newedata->trigger_schema);

  	recursion_depth--;
  	PG_RE_THROW();
*************** write_csvlog(ErrorData *edata)
*** 2259,2264 ****
--- 2423,2455 ----
  	/* 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_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_schema);

  	appendStringInfoChar(&buf, '\n');

*************** send_message_to_server_log(ErrorData *ed
*** 2377,2382 ****
--- 2568,2636 ----
  				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_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_schema)
+ 			{
+ 				log_line_prefix(&buf, edata);
+ 				appendStringInfoString(&buf, _("TRIGGER SCHEMA:  "));
+ 				append_with_tabs(&buf, edata->trigger_schema);
+ 				appendStringInfoChar(&buf, '\n');
+ 			}
  		}
  	}

*************** send_message_to_frontend(ErrorData *edat
*** 2673,2678 ****
--- 2927,2986 ----
  			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_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_schema)
+ 		{
+ 			pq_sendbyte(&msgbuf, PG_DIAG_TRIGGER_SCHEMA);
+ 			err_sendstring(&msgbuf, edata->trigger_schema);
+ 		}
+
  		pq_sendbyte(&msgbuf, '\0');		/* terminator */
  	}
  	else
diff src/include/postgres_ext.h
index b6ebb7a..833c59e
*** a/src/include/postgres_ext.h
--- b/src/include/postgres_ext.h
*************** typedef unsigned int Oid;
*** 55,59 ****
--- 55,68 ----
  #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_SCHEMA	'm'
+ #define PG_DIAG_ROUTINE_NAME		'r'
+ #define PG_DIAG_ROUTINE_SCHEMA		'u'
+ #define PG_DIAG_TRIGGER_NAME		'g'
+ #define PG_DIAG_TRIGGER_SCHEMA		'h'

  #endif
diff src/include/utils/elog.h
index 1bbfd2b..3bfead9
*** a/src/include/utils/elog.h
--- b/src/include/utils/elog.h
*************** extern int	geterrcode(void);
*** 190,195 ****
--- 189,196 ----
  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:
*************** typedef struct ErrorData
*** 321,326 ****
--- 323,337 ----
  	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_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_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 src/include/utils/rel.h
index 4669d8a..82d50e5
*** a/src/include/utils/rel.h
--- b/src/include/utils/rel.h
*************** typedef struct StdRdOptions
*** 394,397 ****
--- 394,404 ----
  extern void RelationIncrementReferenceCount(Relation rel);
  extern void RelationDecrementReferenceCount(Relation rel);

+ extern inline int relation_column_error(Relation rel, const char *colname);
+ extern inline int relation_error(Relation rel);
+ extern inline int constraint_error(Relation rel, const char *ccname);
+ extern inline int constraint_relation_error(Relation rel);
+ extern inline int column_error(const char *cname);
+
+
  #endif   /* REL_H */
diff src/interfaces/libpq/fe-protocol3.c
index 173af2e..6f0a664
*** a/src/interfaces/libpq/fe-protocol3.c
--- b/src/interfaces/libpq/fe-protocol3.c
*************** pqGetErrorNotice3(PGconn *conn, bool isE
*** 980,985 ****
--- 980,1013 ----
  								  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_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_SCHEMA);
+ 		if (val)
+ 			appendPQExpBuffer(&workBuf, libpq_gettext("TRIGGER SCHEMA:  %s\n"), val);
  	}

  	/*
