*** a/doc/src/sgml/libpq.sgml
--- b/doc/src/sgml/libpq.sgml
***************
*** 2515,2521 **** char *PQresultErrorField(const PGresult *res, int fieldcode);
--- 2515,2567 ----
             </para>
            </listitem>
           </varlistentry>
+ 
+          <varlistentry id="libpq-pg-diag-column-name">
+           <term><symbol>PG_DIAG_COLUMN_NAME</></term>
+           <listitem>
+            <para>
+             The name of the column related to the error.
+            </para>
+           </listitem>
+          </varlistentry>
+ 
+          <varlistentry id="libpq-pg-diag-table-name">
+           <term><symbol>PG_DIAG_TABLE_NAME</></term>
+           <listitem>
+            <para>
+             The name of the table related to the error.
+            </para>
+           </listitem>
+          </varlistentry>
+ 
+          <varlistentry id="libpq-pg-diag-schema-name">
+           <term><symbol>PG_DIAG_SCHEMA_NAME</></term>
+           <listitem>
+            <para>
+             The name of the schema where table, related to the error, is defined.
+            </para>
+           </listitem>
+          </varlistentry>
+ 
+          <varlistentry id="libpq-pg-diag-constraint-name">
+           <term><symbol>PG_DIAG_SCHEMA_NAME</></term>
+           <listitem>
+            <para>
+             The name of the constraint related to the error.
+            </para>
+           </listitem>
+          </varlistentry>
+ 
+          <varlistentry id="libpq-pg-diag-constraint-schema">
+           <term><symbol>PG_DIAG_SCHEMA_NAME</></term>
+           <listitem>
+            <para>
+             The schema's name of constraint related to the error.
+            </para>
+           </listitem>
+          </varlistentry>
          </variablelist>
+ 
         </para>
  
         <para>
*** a/doc/src/sgml/plpgsql.sgml
--- b/doc/src/sgml/plpgsql.sgml
***************
*** 2612,2620 **** GET STACKED DIAGNOSTICS <replaceable>variable</replaceable> = <replaceable>item<
         </thead>
         <tbody>
          <row>
!          <entry><literal>RETURNED_SQLSTATE</literal></entry>
           <entry>text</entry>
!          <entry>the SQLSTATE error code of the exception</entry>
          </row>
          <row>
           <entry><literal>MESSAGE_TEXT</literal></entry>
--- 2612,2630 ----
         </thead>
         <tbody>
          <row>
!          <entry><literal>COLUMN_NAME</literal></entry>
           <entry>text</entry>
!          <entry>a name of column related to error</entry>
!         </row>
!         <row>
!          <entry><literal>CONSTRAINT_NAME</literal></entry>
!          <entry>text</entry>
!          <entry>a name of constraint related to error</entry>
!         </row>
!         <row>
!          <entry><literal>CONSTRAINT_SCHEMA</literal></entry>
!          <entry>text</entry>
!          <entry>a schema where is defined a constraint related to error</entry>
          </row>
          <row>
           <entry><literal>MESSAGE_TEXT</literal></entry>
***************
*** 2636,2641 **** GET STACKED DIAGNOSTICS <replaceable>variable</replaceable> = <replaceable>item<
--- 2646,2666 ----
           <entry>text</entry>
           <entry>line(s) of text describing the call stack</entry>
          </row>
+         <row>
+          <entry><literal>RETURNED_SQLSTATE</literal></entry>
+          <entry>text</entry>
+          <entry>the SQLSTATE error code of the exception</entry>
+         </row>
+         <row>
+          <entry><literal>SCHEMA_NAME</literal></entry>
+          <entry>text</entry>
+          <entry>a name of shema where is defined table related to error</entry>
+         </row>
+         <row>
+          <entry><literal>TABLE_NAME</literal></entry>
+          <entry>text</entry>
+          <entry>a name of table related to error</entry>
+         </row>
         </tbody>
        </tgroup>
       </table>
***************
*** 3246,3253 **** RAISE NOTICE 'Calling cs_create_job(%)', v_job_id;
      class="parameter">option</replaceable> = <replaceable
      class="parameter">expression</replaceable> items.  The allowed
      <replaceable class="parameter">option</replaceable> keywords are
!     <literal>MESSAGE</>, <literal>DETAIL</>, <literal>HINT</>, and
!     <literal>ERRCODE</>, while each <replaceable
      class="parameter">expression</replaceable> can be any string-valued
      expression.
      <literal>MESSAGE</> sets the error message text (this option can't
--- 3271,3280 ----
      class="parameter">option</replaceable> = <replaceable
      class="parameter">expression</replaceable> items.  The allowed
      <replaceable class="parameter">option</replaceable> keywords are
!     <literal>COLUMN_NAME</>, <literal>CONSTRAINT_NAME</>,
!     <literal>CONSTRAINT_SCHEMA</>, <literal>DETAIL</>,  <literal>ERRCODE</>,
!     <literal>HINT</>, <literal>MESSAGE</>,  <literal>TABLE_NAME</>, and
!     <literal>SCHEMA_NAME</>, while each <replaceable
      class="parameter">expression</replaceable> can be any string-valued
      expression.
      <literal>MESSAGE</> sets the error message text (this option can't
*** a/doc/src/sgml/protocol.sgml
--- b/doc/src/sgml/protocol.sgml
***************
*** 4682,4687 **** message.
--- 4682,4742 ----
  </listitem>
  </varlistentry>
  
+ <varlistentry>
+ <term>
+ <literal>A</>
+ </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 the table related to error.
+ </para>
+ </listitem>
+ </varlistentry>
+ 
+ <varlistentry>
+ <term>
+ <literal>t</>
+ </term>
+ <listitem>
+ <para>
+         Schema name: the name of schema where is comming table related to the error.
+ </para>
+ </listitem>
+ </varlistentry>
+ 
+ <varlistentry>
+ <term>
+ <literal>N</>
+ </term>
+ <listitem>
+ <para>
+         Constraint name: the name of the constraint related to the error.
+ </para>
+ </listitem>
+ </varlistentry>
+ 
+ <varlistentry>
+ <term>
+ <literal>n</>
+ </term>
+ <listitem>
+ <para>
+         Constraint schema: the name of the schema where is defined a constraint related to the error.
+ </para>
+ </listitem>
+ </varlistentry>
+ 
  </variablelist>
  
  <para>
*** a/doc/src/sgml/sources.sgml
--- b/doc/src/sgml/sources.sgml
***************
*** 298,303 **** ereport(ERROR,
--- 298,314 ----
       includes the current statement already.
      </para>
     </listitem>
+ 
+    <listitem>
+     <para>
+      <function>errstr(int diagnostics_field, const char *str)</function> can be
+      called to specify a some other data like <literal>COLUMN_NAME</>,
+      <literal>TABLE_NAME</>, <literal>SCHEMA_NAME</>, <literal>CONSTRAINT_NAME</>,
+      <literal>CONSTRAINT_SCHEMA</>.
+     </para>
+    </listitem>
+ 
+ 
    </itemizedlist>
     </para>
  
*** a/src/backend/access/nbtree/nbtinsert.c
--- b/src/backend/access/nbtree/nbtinsert.c
***************
*** 23,28 ****
--- 23,29 ----
  #include "storage/lmgr.h"
  #include "storage/predicate.h"
  #include "utils/inval.h"
+ #include "utils/lsyscache.h"
  #include "utils/tqual.h"
  
  
***************
*** 394,400 **** _bt_check_unique(Relation rel, IndexTuple itup, Relation heapRel,
  										RelationGetRelationName(rel)),
  								 errdetail("Key %s already exists.",
  										   BuildIndexValueDescription(rel,
! 														  values, isnull))));
  					}
  				}
  				else if (all_dead)
--- 395,405 ----
  										RelationGetRelationName(rel)),
  								 errdetail("Key %s already exists.",
  										   BuildIndexValueDescription(rel,
! 														  values, isnull)),
! 								 errstr(CONSTRAINT_NAME, RelationGetRelationName(rel)),
! 								 errstr(CONSTRAINT_SCHEMA, get_namespace_name(RelationGetNamespace(rel))),
! 								 errstr(TABLE_NAME, RelationGetRelationName(heapRel)),
! 								 errstr(SCHEMA_NAME, get_namespace_name(RelationGetNamespace(heapRel)))));
  					}
  				}
  				else if (all_dead)
***************
*** 534,540 **** _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.")));
  
  	/*----------
  	 * If we will need to split the page to put the item on this page,
--- 539,549 ----
  				   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."),
! 			 errstr(CONSTRAINT_NAME, RelationGetRelationName(rel)),
! 			 errstr(CONSTRAINT_SCHEMA, get_namespace_name(RelationGetNamespace(rel))),
! 			 errstr(TABLE_NAME, RelationGetRelationName(heapRel)),
! 			 errstr(SCHEMA_NAME, get_namespace_name(RelationGetNamespace(heapRel)))));
  
  	/*----------
  	 * If we will need to split the page to put the item on this page,
*** a/src/backend/commands/typecmds.c
--- b/src/backend/commands/typecmds.c
***************
*** 2570,2575 **** GetDomainConstraints(Oid typeOid)
--- 2570,2576 ----
  	List	   *result = NIL;
  	bool		notNull = false;
  	Relation	conRel;
+ 	Oid		namespaceid =  InvalidOid;
  
  	conRel = heap_open(ConstraintRelationId, AccessShareLock);
  
***************
*** 2595,2601 **** GetDomainConstraints(Oid typeOid)
--- 2596,2605 ----
  
  		/* Test for NOT NULL Constraint */
  		if (typTup->typnotnull)
+ 		{
  			notNull = true;
+ 			namespaceid = typTup->typnamespace;
+ 		}
  
  		/* Look for CHECK Constraints on this domain */
  		ScanKeyInit(&key[0],
***************
*** 2635,2640 **** GetDomainConstraints(Oid typeOid)
--- 2639,2645 ----
  			r = makeNode(DomainConstraintState);
  			r->constrainttype = DOM_CONSTRAINT_CHECK;
  			r->name = pstrdup(NameStr(c->conname));
+ 			r->namespace = c->connamespace;
  			r->check_expr = ExecInitExpr(check_expr, NULL);
  
  			/*
***************
*** 2663,2668 **** GetDomainConstraints(Oid typeOid)
--- 2668,2674 ----
  
  		r->constrainttype = DOM_CONSTRAINT_NOTNULL;
  		r->name = pstrdup("NOT NULL");
+ 		r->namespace = namespaceid;
  		r->check_expr = NULL;
  
  		/* lcons to apply the nullness check FIRST */
*** a/src/backend/executor/execMain.c
--- b/src/backend/executor/execMain.c
***************
*** 1565,1571 **** ExecConstraints(ResultRelInfo *resultRelInfo,
  				ereport(ERROR,
  						(errcode(ERRCODE_NOT_NULL_VIOLATION),
  						 errmsg("null value in column \"%s\" violates not-null constraint",
! 						NameStr(rel->rd_att->attrs[attrChk - 1]->attname))));
  		}
  	}
  
--- 1565,1576 ----
  				ereport(ERROR,
  						(errcode(ERRCODE_NOT_NULL_VIOLATION),
  						 errmsg("null value in column \"%s\" violates not-null constraint",
! 							    NameStr(rel->rd_att->attrs[attrChk - 1]->attname)),
! 						 errstr(COLUMN_NAME,
! 							    NameStr(rel->rd_att->attrs[attrChk - 1]->attname)),
! 						 errstr(TABLE_NAME, RelationGetRelationName(rel)),
! 						 errstr(SCHEMA_NAME,
! 							    get_namespace_name(RelationGetNamespace(rel)))));
  		}
  	}
  
***************
*** 1577,1583 **** ExecConstraints(ResultRelInfo *resultRelInfo,
  			ereport(ERROR,
  					(errcode(ERRCODE_CHECK_VIOLATION),
  					 errmsg("new row for relation \"%s\" violates check constraint \"%s\"",
! 							RelationGetRelationName(rel), failed)));
  	}
  }
  
--- 1582,1594 ----
  			ereport(ERROR,
  					(errcode(ERRCODE_CHECK_VIOLATION),
  					 errmsg("new row for relation \"%s\" violates check constraint \"%s\"",
! 						    RelationGetRelationName(rel), failed),
! 					 errstr(TABLE_NAME, RelationGetRelationName(rel)),
! 					 errstr(SCHEMA_NAME,
! 						    get_namespace_name(RelationGetNamespace(rel))),
! 					 errstr(CONSTRAINT_NAME, failed),
! 					 errstr(CONSTRAINT_SCHEMA,
! 						    get_namespace_name(RelationGetNamespace(rel)))));
  	}
  }
  
*** a/src/backend/executor/execQual.c
--- b/src/backend/executor/execQual.c
***************
*** 3777,3783 **** ExecEvalCoerceToDomain(CoerceToDomainState *cstate, ExprContext *econtext,
  					ereport(ERROR,
  							(errcode(ERRCODE_NOT_NULL_VIOLATION),
  							 errmsg("domain %s does not allow null values",
! 									format_type_be(ctest->resulttype))));
  				break;
  			case DOM_CONSTRAINT_CHECK:
  				{
--- 3777,3785 ----
  					ereport(ERROR,
  							(errcode(ERRCODE_NOT_NULL_VIOLATION),
  							 errmsg("domain %s does not allow null values",
! 									format_type_be(ctest->resulttype)),
! 							 errstr(CONSTRAINT_NAME, con->name),
! 							 errstr(CONSTRAINT_SCHEMA, get_namespace_name(con->namespace))));
  				break;
  			case DOM_CONSTRAINT_CHECK:
  				{
***************
*** 3807,3813 **** ExecEvalCoerceToDomain(CoerceToDomainState *cstate, ExprContext *econtext,
  								(errcode(ERRCODE_CHECK_VIOLATION),
  								 errmsg("value for domain %s violates check constraint \"%s\"",
  										format_type_be(ctest->resulttype),
! 										con->name)));
  					econtext->domainValue_datum = save_datum;
  					econtext->domainValue_isNull = save_isNull;
  
--- 3809,3817 ----
  								(errcode(ERRCODE_CHECK_VIOLATION),
  								 errmsg("value for domain %s violates check constraint \"%s\"",
  										format_type_be(ctest->resulttype),
! 										con->name),
! 								 errstr(CONSTRAINT_NAME, con->name),
! 								 errstr(CONSTRAINT_SCHEMA, get_namespace_name(con->namespace))));
  					econtext->domainValue_datum = save_datum;
  					econtext->domainValue_isNull = save_isNull;
  
*** a/src/backend/utils/adt/ri_triggers.c
--- b/src/backend/utils/adt/ri_triggers.c
***************
*** 244,250 **** static void ri_ReportViolation(RI_QueryKey *qkey, const char *constrname,
  				   HeapTuple violator, TupleDesc tupdesc,
  				   bool spi_err);
  
- 
  /* ----------
   * RI_FKey_check -
   *
--- 244,249 ----
***************
*** 410,416 **** RI_FKey_check(PG_FUNCTION_ARGS)
  							 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);
  
--- 409,421 ----
  							 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."),
! 							 errstr(TABLE_NAME, RelationGetRelationName(trigdata->tg_relation)),
! 							 errstr(SCHEMA_NAME,
! 								    get_namespace_name(RelationGetNamespace(trigdata->tg_relation))),
! 							 errstr(CONSTRAINT_NAME, NameStr(riinfo.conname)),
! 							 errstr(CONSTRAINT_SCHEMA,
! 								    get_namespace_name(RelationGetNamespace(trigdata->tg_relation)))));
  					heap_close(pk_rel, RowShareLock);
  					return PointerGetDatum(NULL);
  
***************
*** 2840,2846 **** 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),
  								constrname),
! 						 errdetail("MATCH FULL does not allow mixing of null and nonnull key values.")));
  		}
  
  		/*
--- 2845,2857 ----
  						 errmsg("insert or update on table \"%s\" violates foreign key constraint \"%s\"",
  								RelationGetRelationName(fk_rel),
  								constrname),
! 						 errdetail("MATCH FULL does not allow mixing of null and nonnull key values."),
! 						 errstr(TABLE_NAME, RelationGetRelationName(fk_rel)),
! 						 errstr(SCHEMA_NAME,
! 							    get_namespace_name(RelationGetNamespace(fk_rel))),
! 						 errstr(CONSTRAINT_NAME, constrname),
! 						 errstr(CONSTRAINT_SCHEMA,
! 							    get_namespace_name(RelationGetNamespace(fk_rel)))));
  		}
  
  		/*
***************
*** 3538,3544 **** ri_ReportViolation(RI_QueryKey *qkey, const char *constrname,
  				 errmsg("insert or update on table \"%s\" violates foreign key constraint \"%s\"",
  						RelationGetRelationName(fk_rel), constrname),
  				 errdetail("No rows were found in \"%s\".",
! 						   RelationGetRelationName(pk_rel))));
  	}
  
  	/* Get printable versions of the keys involved */
--- 3549,3561 ----
  				 errmsg("insert or update on table \"%s\" violates foreign key constraint \"%s\"",
  						RelationGetRelationName(fk_rel), constrname),
  				 errdetail("No rows were found in \"%s\".",
! 						   RelationGetRelationName(pk_rel)),
! 				 errstr(TABLE_NAME, RelationGetRelationName(fk_rel)),
! 				 errstr(SCHEMA_NAME,
! 					    get_namespace_name(RelationGetNamespace(fk_rel))),
! 				 errstr(CONSTRAINT_NAME, constrname),
! 				 errstr(CONSTRAINT_SCHEMA,
! 					    get_namespace_name(RelationGetNamespace(fk_rel)))));
  	}
  
  	/* Get printable versions of the keys involved */
***************
*** 3571,3577 **** ri_ReportViolation(RI_QueryKey *qkey, const char *constrname,
  						RelationGetRelationName(fk_rel), constrname),
  				 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),
--- 3588,3600 ----
  						RelationGetRelationName(fk_rel), constrname),
  				 errdetail("Key (%s)=(%s) is not present in table \"%s\".",
  						   key_names.data, key_values.data,
! 						   RelationGetRelationName(pk_rel)),
! 				 errstr(TABLE_NAME, RelationGetRelationName(fk_rel)),
! 				 errstr(SCHEMA_NAME,
! 					    get_namespace_name(RelationGetNamespace(fk_rel))),
! 				 errstr(CONSTRAINT_NAME, constrname),
! 				 errstr(CONSTRAINT_SCHEMA,
! 					    get_namespace_name(RelationGetNamespace(fk_rel)))));
  	else
  		ereport(ERROR,
  				(errcode(ERRCODE_FOREIGN_KEY_VIOLATION),
***************
*** 3580,3586 **** ri_ReportViolation(RI_QueryKey *qkey, const char *constrname,
  						constrname, RelationGetRelationName(fk_rel)),
  			errdetail("Key (%s)=(%s) is still referenced from table \"%s\".",
  					  key_names.data, key_values.data,
! 					  RelationGetRelationName(fk_rel))));
  }
  
  /* ----------
--- 3603,3615 ----
  						constrname, RelationGetRelationName(fk_rel)),
  			errdetail("Key (%s)=(%s) is still referenced from table \"%s\".",
  					  key_names.data, key_values.data,
! 					  RelationGetRelationName(fk_rel)),
! 				 errstr(TABLE_NAME, RelationGetRelationName(pk_rel)),
! 				 errstr(SCHEMA_NAME,
! 					    get_namespace_name(RelationGetNamespace(pk_rel))),
! 				 errstr(CONSTRAINT_NAME, constrname),
! 				 errstr(CONSTRAINT_SCHEMA,
! 					    get_namespace_name(RelationGetNamespace(fk_rel)))));
  }
  
  /* ----------
*** a/src/backend/utils/error/elog.c
--- b/src/backend/utils/error/elog.c
***************
*** 457,462 **** errfinish(int dummy,...)
--- 457,472 ----
  		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_schema)
+ 		pfree(edata->constraint_schema);
+ 	if (edata->constraint_name)
+ 		pfree(edata->constraint_name);
  
  	errordata_stack_depth--;
  
***************
*** 1016,1021 **** errposition(int cursorpos)
--- 1026,1106 ----
  }
  
  /*
+  * errcatalog_info - add a diagnostics value to the current error
+  */
+ int
+ errcatalog_info(int kind, const char *str)
+ {
+ 	ErrorData  *edata = &errordata[errordata_stack_depth];
+ 	MemoryContext oldcontext;
+ 
+ 	recursion_depth++;
+ 	CHECK_STACK_DEPTH();
+ 	oldcontext = MemoryContextSwitchTo(ErrorContext);
+ 
+ 	/* we don't bother incrementing recursion_depth */
+ 	CHECK_STACK_DEPTH();
+ 
+ 	switch (kind)
+ 	{
+ 		case PG_DIAG_COLUMN_NAME:
+ 			if (edata->column_name)
+ 			{
+ 				pfree(edata->column_name);
+ 				edata->column_name = NULL;
+ 			}
+ 			if (str)
+ 				edata->column_name = MemoryContextStrdup(ErrorContext, str);
+ 			break;
+ 
+ 		case PG_DIAG_TABLE_NAME:
+ 			if (edata->table_name)
+ 			{
+ 				pfree(edata->table_name);
+ 				edata->table_name = NULL;
+ 			}
+ 			if (str)
+ 				edata->table_name = MemoryContextStrdup(ErrorContext, str);
+ 			break;
+ 
+ 		case PG_DIAG_SCHEMA_NAME:
+ 			if (edata->schema_name)
+ 			{
+ 				pfree(edata->schema_name);
+ 				edata->schema_name = NULL;
+ 			}
+ 			if (str)
+ 				edata->schema_name = MemoryContextStrdup(ErrorContext, str);
+ 			break;
+ 
+ 		case PG_DIAG_CONSTRAINT_NAME:
+ 			if (edata->constraint_name)
+ 			{
+ 				pfree(edata->constraint_name);
+ 				edata->constraint_name = NULL;
+ 			}
+ 			if (str)
+ 				edata->constraint_name = MemoryContextStrdup(ErrorContext, str);
+ 			break;
+ 
+ 		case PG_DIAG_CONSTRAINT_SCHEMA:
+ 			if (edata->constraint_schema)
+ 			{
+ 				pfree(edata->constraint_schema);
+ 				edata->constraint_schema = NULL;
+ 			}
+ 			if (str)
+ 				edata->constraint_schema = MemoryContextStrdup(ErrorContext, str);
+ 			break;
+ 	}
+ 
+ 	MemoryContextSwitchTo(oldcontext);
+ 	recursion_depth--;
+ 	return 0;					/* return value does not matter */
+ }
+ 
+ 
+ /*
   * internalerrposition --- add internal cursor position to the current error
   */
  int
***************
*** 1306,1311 **** CopyErrorData(void)
--- 1391,1406 ----
  		newedata->context = pstrdup(newedata->context);
  	if (newedata->internalquery)
  		newedata->internalquery = pstrdup(newedata->internalquery);
+ 	if (edata->column_name)
+ 		newedata->column_name = pstrdup(newedata->column_name);
+ 	if (newedata->table_name)
+ 		newedata->table_name = pstrdup(edata->table_name);
+ 	if (newedata->schema_name)
+ 		newedata->schema_name = pstrdup(newedata->schema_name);
+ 	if (newedata->constraint_schema)
+ 		newedata->constraint_schema = pstrdup(newedata->constraint_schema);
+ 	if (newedata->constraint_name)
+ 		newedata->constraint_name = pstrdup(newedata->constraint_name);
  
  	return newedata;
  }
***************
*** 1331,1336 **** FreeErrorData(ErrorData *edata)
--- 1426,1441 ----
  		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_schema)
+ 		pfree(edata->constraint_schema);
+ 	if (edata->constraint_name)
+ 		pfree(edata->constraint_name);
  	pfree(edata);
  }
  
***************
*** 1403,1408 **** ReThrowError(ErrorData *edata)
--- 1508,1523 ----
  		newedata->context = pstrdup(newedata->context);
  	if (newedata->internalquery)
  		newedata->internalquery = pstrdup(newedata->internalquery);
+ 	if (edata->column_name)
+ 		newedata->column_name = pstrdup(newedata->column_name);
+ 	if (newedata->table_name)
+ 		newedata->table_name = pstrdup(edata->table_name);
+ 	if (newedata->schema_name)
+ 		newedata->schema_name = pstrdup(newedata->schema_name);
+ 	if (newedata->constraint_schema)
+ 		newedata->constraint_schema = pstrdup(newedata->constraint_schema);
+ 	if (newedata->constraint_name)
+ 		newedata->constraint_name = pstrdup(newedata->constraint_name);
  
  	recursion_depth--;
  	PG_RE_THROW();
***************
*** 2223,2228 **** write_csvlog(ErrorData *edata)
--- 2338,2368 ----
  	/* application name */
  	if (application_name)
  		appendCSVLiteral(&buf, application_name);
+ 	appendStringInfoChar(&buf, ',');
+ 
+ 	/* column name */
+ 	if (Log_error_verbosity >= PGERROR_VERBOSE)
+ 		appendCSVLiteral(&buf, edata->column_name);
+ 	appendStringInfoChar(&buf, ',');
+ 
+ 	/* table name */
+ 	if (Log_error_verbosity >= PGERROR_VERBOSE)
+ 		appendCSVLiteral(&buf, edata->table_name);
+ 	appendStringInfoChar(&buf, ',');
+ 
+ 	/* schema name */
+ 	if (Log_error_verbosity >= PGERROR_VERBOSE)
+ 		appendCSVLiteral(&buf, edata->schema_name);
+ 	appendStringInfoChar(&buf, ',');
+ 
+ 	/* constraint name */
+ 	if (Log_error_verbosity >= PGERROR_VERBOSE)
+ 		appendCSVLiteral(&buf, edata->constraint_name);
+ 	appendStringInfoChar(&buf, ',');
+ 
+ 	/* constraint schema */
+ 	if (Log_error_verbosity >= PGERROR_VERBOSE)
+ 		appendCSVLiteral(&buf, edata->constraint_schema);
  
  	appendStringInfoChar(&buf, '\n');
  
***************
*** 2341,2346 **** send_message_to_server_log(ErrorData *edata)
--- 2481,2521 ----
  				appendStringInfo(&buf, _("LOCATION:  %s:%d\n"),
  								 edata->filename, edata->lineno);
  			}
+ 			if (edata->column_name)
+ 			{
+ 				log_line_prefix(&buf, edata);
+ 				appendStringInfoString(&buf, _("COLUMN:  "));
+ 				append_with_tabs(&buf, edata->column_name);
+ 				appendStringInfoChar(&buf, '\n');
+ 			}
+ 			if (edata->table_name)
+ 			{
+ 				log_line_prefix(&buf, edata);
+ 				appendStringInfoString(&buf, _("TABLE:  "));
+ 				append_with_tabs(&buf, edata->table_name);
+ 				appendStringInfoChar(&buf, '\n');
+ 			}
+ 			if (edata->schema_name)
+ 			{
+ 				log_line_prefix(&buf, edata);
+ 				appendStringInfoString(&buf, _("SCHEMA:  "));
+ 				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');
+ 			}
  		}
  	}
  
***************
*** 2618,2623 **** send_message_to_frontend(ErrorData *edata)
--- 2793,2828 ----
  			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);
+ 		}
+ 
  		pq_sendbyte(&msgbuf, '\0');		/* terminator */
  	}
  	else
*** a/src/include/nodes/execnodes.h
--- b/src/include/nodes/execnodes.h
***************
*** 941,946 **** typedef struct DomainConstraintState
--- 941,947 ----
  	NodeTag		type;
  	DomainConstraintType constrainttype;		/* constraint type */
  	char	   *name;			/* name of constraint (for error msgs) */
+ 	Oid	   namespace;			/* schema of constraint (for error msgs) */
  	ExprState  *check_expr;		/* for CHECK, a boolean expression */
  } DomainConstraintState;
  
*** a/src/include/postgres_ext.h
--- b/src/include/postgres_ext.h
***************
*** 55,59 **** typedef unsigned int Oid;
--- 55,64 ----
  #define PG_DIAG_SOURCE_FILE		'F'
  #define PG_DIAG_SOURCE_LINE		'L'
  #define PG_DIAG_SOURCE_FUNCTION 'R'
+ #define PG_DIAG_COLUMN_NAME		'A'
+ #define PG_DIAG_TABLE_NAME		'T'
+ #define PG_DIAG_SCHEMA_NAME		't'
+ #define PG_DIAG_CONSTRAINT_NAME		'N'
+ #define PG_DIAG_CONSTRAINT_SCHEMA	'n'
  
  #endif
*** a/src/include/utils/elog.h
--- b/src/include/utils/elog.h
***************
*** 182,187 **** extern int	errhidestmt(bool hide_stmt);
--- 182,191 ----
  
  extern int	errfunction(const char *funcname);
  extern int	errposition(int cursorpos);
+ extern int	errcatalog_info(int kind, const char *str);
+ 
+ #define errstr(kind, str)	\
+ 	errcatalog_info(PG_DIAG_##kind, str)
  
  extern int	internalerrposition(int cursorpos);
  extern int	internalerrquery(const char *query);
***************
*** 321,326 **** typedef struct ErrorData
--- 325,335 ----
  	char	   *detail_log;		/* detail error message for server log only */
  	char	   *hint;			/* hint message */
  	char	   *context;		/* context message */
+ 	char		*column_name;		/* name of column related to error or empty string */
+ 	char		*table_name;		/* name of table related to error */
+ 	char		*schema_name;		/* name of schema where is a table related to error */
+ 	char		*constraint_schema;	/* schema of constraint or empty string */
+ 	char		*constraint_name;	/* name of constraint of empty string */
  	int			cursorpos;		/* cursor index into query string */
  	int			internalpos;	/* cursor index into internalquery */
  	char	   *internalquery;	/* text of internally-generated query */
*** a/src/interfaces/libpq/fe-protocol3.c
--- b/src/interfaces/libpq/fe-protocol3.c
***************
*** 856,861 **** pqGetErrorNotice3(PGconn *conn, bool isError)
--- 856,876 ----
  								  valf, vall);
  			appendPQExpBufferChar(&workBuf, '\n');
  		}
+ 		val = PQresultErrorField(res, PG_DIAG_COLUMN_NAME);
+ 		if (val)
+ 			appendPQExpBuffer(&workBuf, libpq_gettext("COLUMN: %s\n"), val);
+ 		val = PQresultErrorField(res, PG_DIAG_TABLE_NAME);
+ 		if (val)
+ 			appendPQExpBuffer(&workBuf, libpq_gettext("TABLE: %s\n"), val);
+ 		val = PQresultErrorField(res, PG_DIAG_SCHEMA_NAME);
+ 		if (val)
+ 			appendPQExpBuffer(&workBuf, libpq_gettext("SCHEMA: %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);
  	}
  
  	/*
*** a/src/pl/plpgsql/src/gram.y
--- b/src/pl/plpgsql/src/gram.y
***************
*** 250,256 **** static	List			*read_raise_options(void);
--- 250,259 ----
  %token <keyword>	K_CASE
  %token <keyword>	K_CLOSE
  %token <keyword>	K_COLLATE
+ %token <keyword>	K_COLUMN_NAME
  %token <keyword>	K_CONSTANT
+ %token <keyword>	K_CONSTRAINT_NAME
+ %token <keyword>	K_CONSTRAINT_SCHEMA
  %token <keyword>	K_CONTINUE
  %token <keyword>	K_CURRENT
  %token <keyword>	K_CURSOR
***************
*** 310,320 **** static	List			*read_raise_options(void);
--- 313,325 ----
  %token <keyword>	K_REVERSE
  %token <keyword>	K_ROWTYPE
  %token <keyword>	K_ROW_COUNT
+ %token <keyword>	K_SCHEMA_NAME
  %token <keyword>	K_SCROLL
  %token <keyword>	K_SLICE
  %token <keyword>	K_SQLSTATE
  %token <keyword>	K_STACKED
  %token <keyword>	K_STRICT
+ %token <keyword>	K_TABLE_NAME
  %token <keyword>	K_THEN
  %token <keyword>	K_TO
  %token <keyword>	K_TYPE
***************
*** 876,881 **** stmt_getdiag	: K_GET getdiag_area_opt K_DIAGNOSTICS getdiag_list ';'
--- 881,891 ----
  								case PLPGSQL_GETDIAG_ERROR_HINT:
  								case PLPGSQL_GETDIAG_RETURNED_SQLSTATE:
  								case PLPGSQL_GETDIAG_MESSAGE_TEXT:
+ 								case PLPGSQL_GETDIAG_COLUMN_NAME:
+ 								case PLPGSQL_GETDIAG_CONSTRAINT_NAME:
+ 								case PLPGSQL_GETDIAG_CONSTRAINT_SCHEMA:
+ 								case PLPGSQL_GETDIAG_SCHEMA_NAME:
+ 								case PLPGSQL_GETDIAG_TABLE_NAME:
  									if (!new->is_stacked)
  										ereport(ERROR,
  												(errcode(ERRCODE_SYNTAX_ERROR),
***************
*** 955,960 **** getdiag_item :
--- 965,985 ----
  						else if (tok_is_keyword(tok, &yylval,
  												K_RETURNED_SQLSTATE, "returned_sqlstate"))
  							$$ = PLPGSQL_GETDIAG_RETURNED_SQLSTATE;
+ 						else if (tok_is_keyword(tok, &yylval,
+ 												K_COLUMN_NAME, "column_name"))
+ 							$$ = PLPGSQL_GETDIAG_COLUMN_NAME;
+ 						else if (tok_is_keyword(tok, &yylval,
+ 												K_CONSTRAINT_NAME, "constraint_name"))
+ 							$$ = PLPGSQL_GETDIAG_CONSTRAINT_NAME;
+ 						else if (tok_is_keyword(tok, &yylval,
+ 												K_CONSTRAINT_SCHEMA, "constraint_schema"))
+ 							$$ = PLPGSQL_GETDIAG_CONSTRAINT_SCHEMA;
+ 						else if (tok_is_keyword(tok, &yylval,
+ 												K_SCHEMA_NAME, "schema_name"))
+ 							$$ = PLPGSQL_GETDIAG_SCHEMA_NAME;
+ 						else if (tok_is_keyword(tok, &yylval,
+ 												K_TABLE_NAME, "table_name"))
+ 							$$ = PLPGSQL_GETDIAG_TABLE_NAME;
  						else
  							yyerror("unrecognized GET DIAGNOSTICS item");
  					}
***************
*** 2212,2218 **** unreserved_keyword	:
--- 2237,2246 ----
  				| K_ALIAS
  				| K_ARRAY
  				| K_BACKWARD
+ 				| K_COLUMN_NAME
  				| K_CONSTANT
+ 				| K_CONSTRAINT_NAME
+ 				| K_CONSTRAINT_SCHEMA
  				| K_CURRENT
  				| K_CURSOR
  				| K_DEBUG
***************
*** 2244,2253 **** unreserved_keyword	:
--- 2272,2283 ----
  				| K_REVERSE
  				| K_ROW_COUNT
  				| K_ROWTYPE
+ 				| K_SCHEMA_NAME
  				| K_SCROLL
  				| K_SLICE
  				| K_SQLSTATE
  				| K_STACKED
+ 				| K_TABLE_NAME
  				| K_TYPE
  				| K_USE_COLUMN
  				| K_USE_VARIABLE
***************
*** 3463,3468 **** read_raise_options(void)
--- 3493,3513 ----
  		else if (tok_is_keyword(tok, &yylval,
  								K_HINT, "hint"))
  			opt->opt_type = PLPGSQL_RAISEOPTION_HINT;
+ 		else if (tok_is_keyword(tok, &yylval,
+ 								K_COLUMN_NAME, "column_name"))
+ 			opt->opt_type = PLPGSQL_RAISEOPTION_COLUMN_NAME;
+ 		else if (tok_is_keyword(tok, &yylval,
+ 								K_CONSTRAINT_NAME, "constraint_name"))
+ 			opt->opt_type = PLPGSQL_RAISEOPTION_CONSTRAINT_NAME;
+ 		else if (tok_is_keyword(tok, &yylval,
+ 								K_CONSTRAINT_SCHEMA, "constraint_schema"))
+ 			opt->opt_type = PLPGSQL_RAISEOPTION_CONSTRAINT_SCHEMA;
+ 		else if (tok_is_keyword(tok, &yylval,
+ 								K_SCHEMA_NAME, "schema_name"))
+ 			opt->opt_type = PLPGSQL_RAISEOPTION_SCHEMA_NAME;
+ 		else if (tok_is_keyword(tok, &yylval,
+ 								K_TABLE_NAME, "table_name"))
+ 			opt->opt_type = PLPGSQL_RAISEOPTION_TABLE_NAME;
  		else
  			yyerror("unrecognized RAISE statement option");
  
*** a/src/pl/plpgsql/src/pl_exec.c
--- b/src/pl/plpgsql/src/pl_exec.c
***************
*** 1488,1493 **** exec_stmt_getdiag(PLpgSQL_execstate *estate, PLpgSQL_stmt_getdiag *stmt)
--- 1488,1518 ----
  									 estate->cur_error->message);
  				break;
  
+ 			case PLPGSQL_GETDIAG_COLUMN_NAME:
+ 				exec_assign_c_string(estate, var,
+ 									 estate->cur_error->column_name);
+ 				break;
+ 
+ 			case PLPGSQL_GETDIAG_CONSTRAINT_NAME:
+ 				exec_assign_c_string(estate, var,
+ 									 estate->cur_error->constraint_name);
+ 				break;
+ 
+ 			case PLPGSQL_GETDIAG_CONSTRAINT_SCHEMA:
+ 				exec_assign_c_string(estate, var,
+ 									 estate->cur_error->constraint_schema);
+ 				break;
+ 
+ 			case PLPGSQL_GETDIAG_SCHEMA_NAME:
+ 				exec_assign_c_string(estate, var,
+ 									 estate->cur_error->schema_name);
+ 				break;
+ 
+ 			case PLPGSQL_GETDIAG_TABLE_NAME:
+ 				exec_assign_c_string(estate, var,
+ 									 estate->cur_error->table_name);
+ 				break;
+ 
  			default:
  				elog(ERROR, "unrecognized diagnostic item kind: %d",
  					 diag_item->kind);
***************
*** 2661,2666 **** exec_stmt_raise(PLpgSQL_execstate *estate, PLpgSQL_stmt_raise *stmt)
--- 2686,2696 ----
  	char	   *err_message = NULL;
  	char	   *err_detail = NULL;
  	char	   *err_hint = NULL;
+ 	char	   *err_column_name = NULL;
+ 	char	   *err_constraint_name = NULL;
+ 	char	   *err_constraint_schema = NULL;
+ 	char	   *err_schema_name = NULL;
+ 	char	   *err_table_name = NULL;
  	ListCell   *lc;
  
  	/* RAISE with no parameters: re-throw current exception */
***************
*** 2798,2803 **** exec_stmt_raise(PLpgSQL_execstate *estate, PLpgSQL_stmt_raise *stmt)
--- 2828,2873 ----
  									"HINT")));
  				err_hint = pstrdup(extval);
  				break;
+ 			case PLPGSQL_RAISEOPTION_COLUMN_NAME:
+ 				if (err_column_name)
+ 					ereport(ERROR,
+ 							(errcode(ERRCODE_SYNTAX_ERROR),
+ 							 errmsg("RAISE option already specified: %s",
+ 									"COLUMN_NAME")));
+ 				err_column_name = pstrdup(extval);
+ 				break;
+ 			case PLPGSQL_RAISEOPTION_CONSTRAINT_NAME:
+ 				if (err_constraint_name)
+ 					ereport(ERROR,
+ 							(errcode(ERRCODE_SYNTAX_ERROR),
+ 							 errmsg("RAISE option already specified: %s",
+ 									"CONSTRAINT_NAME")));
+ 				err_constraint_name = pstrdup(extval);
+ 				break;
+ 			case PLPGSQL_RAISEOPTION_CONSTRAINT_SCHEMA:
+ 				if (err_constraint_schema)
+ 					ereport(ERROR,
+ 							(errcode(ERRCODE_SYNTAX_ERROR),
+ 							 errmsg("RAISE option already specified: %s",
+ 									"CONSTRAINT_SCHEMA")));
+ 				err_constraint_schema = pstrdup(extval);
+ 				break;
+ 			case PLPGSQL_RAISEOPTION_SCHEMA_NAME:
+ 				if (err_schema_name)
+ 					ereport(ERROR,
+ 							(errcode(ERRCODE_SYNTAX_ERROR),
+ 							 errmsg("RAISE option already specified: %s",
+ 									"SCHEMA_NAME")));
+ 				err_schema_name = pstrdup(extval);
+ 				break;
+ 			case PLPGSQL_RAISEOPTION_TABLE_NAME:
+ 				if (err_table_name)
+ 					ereport(ERROR,
+ 							(errcode(ERRCODE_SYNTAX_ERROR),
+ 							 errmsg("RAISE option already specified: %s",
+ 									"TABLE_NAME")));
+ 				err_table_name = pstrdup(extval);
+ 				break;
  			default:
  				elog(ERROR, "unrecognized raise option: %d", opt->opt_type);
  		}
***************
*** 2830,2836 **** exec_stmt_raise(PLpgSQL_execstate *estate, PLpgSQL_stmt_raise *stmt)
  			(err_code ? errcode(err_code) : 0,
  			 errmsg_internal("%s", err_message),
  			 (err_detail != NULL) ? errdetail_internal("%s", err_detail) : 0,
! 			 (err_hint != NULL) ? errhint("%s", err_hint) : 0));
  
  	estate->err_text = NULL;	/* un-suppress... */
  
--- 2900,2911 ----
  			(err_code ? errcode(err_code) : 0,
  			 errmsg_internal("%s", err_message),
  			 (err_detail != NULL) ? errdetail_internal("%s", err_detail) : 0,
! 			 (err_hint != NULL) ? errhint("%s", err_hint) : 0,
! 			 (err_column_name != NULL) ? errstr(COLUMN_NAME, err_column_name) : 0,
! 			 (err_constraint_name != NULL) ? errstr(CONSTRAINT_NAME, err_constraint_name) : 0,
! 			 (err_constraint_schema != NULL) ? errstr(CONSTRAINT_SCHEMA, err_constraint_schema) : 0,
! 			 (err_schema_name != NULL) ? errstr(SCHEMA_NAME, err_schema_name) : 0,
! 			 (err_table_name != NULL) ? errstr(TABLE_NAME, err_table_name) : 0));
  
  	estate->err_text = NULL;	/* un-suppress... */
  
***************
*** 2842,2847 **** exec_stmt_raise(PLpgSQL_execstate *estate, PLpgSQL_stmt_raise *stmt)
--- 2917,2932 ----
  		pfree(err_detail);
  	if (err_hint != NULL)
  		pfree(err_hint);
+ 	if (err_column_name != NULL)
+ 		pfree(err_column_name);
+ 	if (err_constraint_name != NULL)
+ 		pfree(err_constraint_name);
+ 	if (err_constraint_schema != NULL)
+ 		pfree(err_constraint_name);
+ 	if (err_schema_name != NULL)
+ 		pfree(err_schema_name);
+ 	if (err_table_name != NULL)
+ 		pfree(err_table_name);
  
  	return PLPGSQL_RC_OK;
  }
*** a/src/pl/plpgsql/src/pl_funcs.c
--- b/src/pl/plpgsql/src/pl_funcs.c
***************
*** 287,292 **** plpgsql_getdiag_kindname(int kind)
--- 287,302 ----
  			return "RETURNED_SQLSTATE";
  		case PLPGSQL_GETDIAG_MESSAGE_TEXT:
  			return "MESSAGE_TEXT";
+ 		case PLPGSQL_GETDIAG_COLUMN_NAME:
+ 			return "COLUMN_NAME";
+ 		case PLPGSQL_GETDIAG_CONSTRAINT_NAME:
+ 			return "CONSTRAINT_NAME";
+ 		case PLPGSQL_GETDIAG_CONSTRAINT_SCHEMA:
+ 			return "CONSTRAINT_SCHEMA";
+ 		case PLPGSQL_GETDIAG_SCHEMA_NAME:
+ 			return "SCHEMA_NAME";
+ 		case PLPGSQL_GETDIAG_TABLE_NAME:
+ 			return "TABLE_NAME";
  	}
  
  	return "unknown";
*** a/src/pl/plpgsql/src/pl_scanner.c
--- b/src/pl/plpgsql/src/pl_scanner.c
***************
*** 109,115 **** static const ScanKeyword unreserved_keywords[] = {
--- 109,118 ----
  	PG_KEYWORD("alias", K_ALIAS, UNRESERVED_KEYWORD)
  	PG_KEYWORD("array", K_ARRAY, UNRESERVED_KEYWORD)
  	PG_KEYWORD("backward", K_BACKWARD, UNRESERVED_KEYWORD)
+ 	PG_KEYWORD("column_name", K_COLUMN_NAME, UNRESERVED_KEYWORD)
  	PG_KEYWORD("constant", K_CONSTANT, UNRESERVED_KEYWORD)
+ 	PG_KEYWORD("constraint_name", K_CONSTRAINT_NAME, UNRESERVED_KEYWORD)
+ 	PG_KEYWORD("constraint_schema", K_CONSTRAINT_SCHEMA, UNRESERVED_KEYWORD)
  	PG_KEYWORD("current", K_CURRENT, UNRESERVED_KEYWORD)
  	PG_KEYWORD("cursor", K_CURSOR, UNRESERVED_KEYWORD)
  	PG_KEYWORD("debug", K_DEBUG, UNRESERVED_KEYWORD)
***************
*** 141,150 **** static const ScanKeyword unreserved_keywords[] = {
--- 144,155 ----
  	PG_KEYWORD("reverse", K_REVERSE, UNRESERVED_KEYWORD)
  	PG_KEYWORD("row_count", K_ROW_COUNT, UNRESERVED_KEYWORD)
  	PG_KEYWORD("rowtype", K_ROWTYPE, UNRESERVED_KEYWORD)
+ 	PG_KEYWORD("schema_name", K_SCHEMA_NAME, UNRESERVED_KEYWORD)
  	PG_KEYWORD("scroll", K_SCROLL, UNRESERVED_KEYWORD)
  	PG_KEYWORD("slice", K_SLICE, UNRESERVED_KEYWORD)
  	PG_KEYWORD("sqlstate", K_SQLSTATE, UNRESERVED_KEYWORD)
  	PG_KEYWORD("stacked", K_STACKED, UNRESERVED_KEYWORD)
+ 	PG_KEYWORD("table_name", K_TABLE_NAME, UNRESERVED_KEYWORD)
  	PG_KEYWORD("type", K_TYPE, UNRESERVED_KEYWORD)
  	PG_KEYWORD("use_column", K_USE_COLUMN, UNRESERVED_KEYWORD)
  	PG_KEYWORD("use_variable", K_USE_VARIABLE, UNRESERVED_KEYWORD)
*** a/src/pl/plpgsql/src/plpgsql.h
--- b/src/pl/plpgsql/src/plpgsql.h
***************
*** 131,137 **** enum
  	PLPGSQL_GETDIAG_ERROR_DETAIL,
  	PLPGSQL_GETDIAG_ERROR_HINT,
  	PLPGSQL_GETDIAG_RETURNED_SQLSTATE,
! 	PLPGSQL_GETDIAG_MESSAGE_TEXT
  };
  
  /* --------
--- 131,142 ----
  	PLPGSQL_GETDIAG_ERROR_DETAIL,
  	PLPGSQL_GETDIAG_ERROR_HINT,
  	PLPGSQL_GETDIAG_RETURNED_SQLSTATE,
! 	PLPGSQL_GETDIAG_MESSAGE_TEXT,
! 	PLPGSQL_GETDIAG_COLUMN_NAME,
! 	PLPGSQL_GETDIAG_CONSTRAINT_NAME,
! 	PLPGSQL_GETDIAG_CONSTRAINT_SCHEMA,
! 	PLPGSQL_GETDIAG_SCHEMA_NAME,
! 	PLPGSQL_GETDIAG_TABLE_NAME
  };
  
  /* --------
***************
*** 143,149 **** enum
  	PLPGSQL_RAISEOPTION_ERRCODE,
  	PLPGSQL_RAISEOPTION_MESSAGE,
  	PLPGSQL_RAISEOPTION_DETAIL,
! 	PLPGSQL_RAISEOPTION_HINT
  };
  
  /* --------
--- 148,159 ----
  	PLPGSQL_RAISEOPTION_ERRCODE,
  	PLPGSQL_RAISEOPTION_MESSAGE,
  	PLPGSQL_RAISEOPTION_DETAIL,
! 	PLPGSQL_RAISEOPTION_HINT,
! 	PLPGSQL_RAISEOPTION_COLUMN_NAME,
! 	PLPGSQL_RAISEOPTION_CONSTRAINT_NAME,
! 	PLPGSQL_RAISEOPTION_CONSTRAINT_SCHEMA,
! 	PLPGSQL_RAISEOPTION_SCHEMA_NAME,
! 	PLPGSQL_RAISEOPTION_TABLE_NAME
  };
  
  /* --------
*** a/src/test/regress/expected/plpgsql.out
--- b/src/test/regress/expected/plpgsql.out
***************
*** 4509,4511 **** NOTICE:  {"(35,78)","(88,76)"}
--- 4509,4686 ----
  
  drop function foreach_test(anyarray);
  drop type xy_tuple;
+ -- test a new fields in get diagnostics statement
+ create or replace function getdiagtest_raise()
+ returns void as $$
+ begin
+   raise exception 'some plpgsql exception'
+     using column_name = 'some column name',
+           constraint_name = 'some constraint name',
+           constraint_schema = 'some constraint schema',
+           table_name = 'some table name',
+           schema_name = 'some schema name';
+ end;
+ $$ language plpgsql;
+ create or replace function getdiagtest()
+ returns void as $$
+ declare
+   _column_name text;
+   _constraint_name text;
+   _constraint_schema text;
+   _table_name text;
+   _schema_name text;
+   _message_text text;
+ begin
+   begin
+     perform getdiagtest_raise();
+   exception when raise_exception then
+     get stacked diagnostics
+       _message_text = MESSAGE_TEXT,
+       _column_name = COLUMN_NAME,
+       _constraint_name = CONSTRAINT_NAME,
+       _constraint_schema = CONSTRAINT_SCHEMA,
+       _table_name = TABLE_NAME,
+       _schema_name = SCHEMA_NAME;
+   end;
+   raise notice 'message text: %, column name: %, constraint name: %, constraint schema: %, table name: %, schema name: %',
+     quote_literal(_message_text),
+     quote_literal(_column_name),
+     quote_literal(_constraint_name),
+     quote_literal(_constraint_schema),
+     quote_literal(_table_name),
+     quote_literal(_schema_name);
+ end;
+ $$ language plpgsql;
+ select getdiagtest();
+ NOTICE:  message text: 'some plpgsql exception', column name: 'some column name', constraint name: 'some constraint name', constraint schema: 'some constraint schema', table name: 'some table name', schema name: 'some schema name'
+  getdiagtest 
+ -------------
+  
+ (1 row)
+ 
+ drop function getdiagtest_raise();
+ drop function getdiagtest();
+ -- real test
+ create table diagtest_alfa(
+ 	id int primary key,
+ 	v1 int not null check (v1 > 10),
+ 	v2 int,
+ 	constraint v1_is_greater_than_v2 check (v1 > v2)
+ );
+ NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "diagtest_alfa_pkey" for table "diagtest_alfa"
+ create table diagtest_beta(alfa_id int references diagtest_alfa(id));
+ create or replace function diagtest(int)
+ returns void as $$
+ declare
+   _column_name text;
+   _constraint_name text;
+   _table_name text;
+   _schema_name text;
+   _constraint_schema text;
+ begin
+   begin
+     case $1
+       when 1 then
+         insert into diagtest_alfa values(1,20,3); -- ok
+       when 2 then
+         insert into diagtest_alfa values(2, null, null);
+       when 3 then
+         insert into diagtest_alfa values(2, 1, null);
+       when 4 then
+         insert into diagtest_alfa values(2, 1, 20);
+       when 5 then
+         insert into diagtest_beta values(1); -- ok
+       when 6 then
+         insert into diagtest_beta values(3);
+       when 7 then
+         delete from diagtest_alfa where id = 1;
+     end case;
+   exception when others then
+     get stacked diagnostics
+       _column_name = COLUMN_NAME,
+       _constraint_name = CONSTRAINT_NAME,
+       _constraint_schema = CONSTRAINT_SCHEMA,
+       _table_name = TABLE_NAME,
+       _schema_name = SCHEMA_NAME;
+   RAISE NOTICE e'column name: %\nconstraint name: %\nconstraint schema: %\ntable name: %\nschema name: %',
+     quote_literal(_column_name),
+     quote_literal(_constraint_name),
+     quote_literal(_constraint_schema),
+     quote_literal(_table_name),
+     quote_literal(_schema_name);
+     raise;
+   end;
+ end;
+ $$ language plpgsql;
+ select diagtest(1); -- ok
+  diagtest 
+ ----------
+  
+ (1 row)
+ 
+ select diagtest(1); -- fails - not unique
+ NOTICE:  column name: ''
+ constraint name: 'diagtest_alfa_pkey'
+ constraint schema: 'public'
+ table name: 'diagtest_alfa'
+ schema name: 'public'
+ ERROR:  duplicate key value violates unique constraint "diagtest_alfa_pkey"
+ DETAIL:  Key (id)=(1) already exists.
+ CONTEXT:  SQL statement "insert into diagtest_alfa values(1,20,3)"
+ PL/pgSQL function "diagtest" line 12 at SQL statement
+ select diagtest(2); -- fails - not null
+ NOTICE:  column name: 'v1'
+ constraint name: ''
+ constraint schema: ''
+ table name: 'diagtest_alfa'
+ schema name: 'public'
+ ERROR:  null value in column "v1" violates not-null constraint
+ CONTEXT:  SQL statement "insert into diagtest_alfa values(2, null, null)"
+ PL/pgSQL function "diagtest" line 14 at SQL statement
+ select diagtest(3); -- fails - column's check constraint
+ NOTICE:  column name: ''
+ constraint name: 'diagtest_alfa_v1_check'
+ constraint schema: 'public'
+ table name: 'diagtest_alfa'
+ schema name: 'public'
+ ERROR:  new row for relation "diagtest_alfa" violates check constraint "diagtest_alfa_v1_check"
+ CONTEXT:  SQL statement "insert into diagtest_alfa values(2, 1, null)"
+ PL/pgSQL function "diagtest" line 16 at SQL statement
+ select diagtest(4); -- fails - table's check constraint
+ NOTICE:  column name: ''
+ constraint name: 'v1_is_greater_than_v2'
+ constraint schema: 'public'
+ table name: 'diagtest_alfa'
+ schema name: 'public'
+ ERROR:  new row for relation "diagtest_alfa" violates check constraint "v1_is_greater_than_v2"
+ CONTEXT:  SQL statement "insert into diagtest_alfa values(2, 1, 20)"
+ PL/pgSQL function "diagtest" line 18 at SQL statement
+ select diagtest(5); -- ok
+  diagtest 
+ ----------
+  
+ (1 row)
+ 
+ select diagtest(6); -- fails FK
+ NOTICE:  column name: ''
+ constraint name: 'diagtest_beta_alfa_id_fkey'
+ constraint schema: 'public'
+ table name: 'diagtest_beta'
+ schema name: 'public'
+ ERROR:  insert or update on table "diagtest_beta" violates foreign key constraint "diagtest_beta_alfa_id_fkey"
+ DETAIL:  Key (alfa_id)=(3) is not present in table "diagtest_alfa".
+ CONTEXT:  SQL statement "insert into diagtest_beta values(3)"
+ PL/pgSQL function "diagtest" line 22 at SQL statement
+ select diagtest(7); -- fails PK
+ NOTICE:  column name: ''
+ constraint name: 'diagtest_beta_alfa_id_fkey'
+ constraint schema: 'public'
+ table name: 'diagtest_alfa'
+ schema name: 'public'
+ ERROR:  update or delete on table "diagtest_alfa" violates foreign key constraint "diagtest_beta_alfa_id_fkey" on table "diagtest_beta"
+ DETAIL:  Key (id)=(1) is still referenced from table "diagtest_beta".
+ CONTEXT:  SQL statement "delete from diagtest_alfa where id = 1"
+ PL/pgSQL function "diagtest" line 24 at SQL statement
+ drop function diagtest(int);
+ drop table diagtest_beta;
+ drop table diagtest_alfa;
*** a/src/test/regress/sql/plpgsql.sql
--- b/src/test/regress/sql/plpgsql.sql
***************
*** 3559,3561 **** select foreach_test(ARRAY[[(10,20),(40,69)],[(35,78),(88,76)]]::xy_tuple[]);
--- 3559,3680 ----
  
  drop function foreach_test(anyarray);
  drop type xy_tuple;
+ 
+ -- test a new fields in get diagnostics statement
+ create or replace function getdiagtest_raise()
+ returns void as $$
+ begin
+   raise exception 'some plpgsql exception'
+     using column_name = 'some column name',
+           constraint_name = 'some constraint name',
+           constraint_schema = 'some constraint schema',
+           table_name = 'some table name',
+           schema_name = 'some schema name';
+ end;
+ $$ language plpgsql;
+ 
+ create or replace function getdiagtest()
+ returns void as $$
+ declare
+   _column_name text;
+   _constraint_name text;
+   _constraint_schema text;
+   _table_name text;
+   _schema_name text;
+   _message_text text;
+ begin
+   begin
+     perform getdiagtest_raise();
+   exception when raise_exception then
+     get stacked diagnostics
+       _message_text = MESSAGE_TEXT,
+       _column_name = COLUMN_NAME,
+       _constraint_name = CONSTRAINT_NAME,
+       _constraint_schema = CONSTRAINT_SCHEMA,
+       _table_name = TABLE_NAME,
+       _schema_name = SCHEMA_NAME;
+   end;
+   raise notice 'message text: %, column name: %, constraint name: %, constraint schema: %, table name: %, schema name: %',
+     quote_literal(_message_text),
+     quote_literal(_column_name),
+     quote_literal(_constraint_name),
+     quote_literal(_constraint_schema),
+     quote_literal(_table_name),
+     quote_literal(_schema_name);
+ end;
+ $$ language plpgsql;
+ 
+ select getdiagtest();
+ 
+ drop function getdiagtest_raise();
+ drop function getdiagtest();
+ 
+ -- real test
+ 
+ create table diagtest_alfa(
+ 	id int primary key,
+ 	v1 int not null check (v1 > 10),
+ 	v2 int,
+ 
+ 	constraint v1_is_greater_than_v2 check (v1 > v2)
+ );
+ 
+ create table diagtest_beta(alfa_id int references diagtest_alfa(id));
+ 
+ create or replace function diagtest(int)
+ returns void as $$
+ declare
+   _column_name text;
+   _constraint_name text;
+   _table_name text;
+   _schema_name text;
+   _constraint_schema text;
+ begin
+   begin
+     case $1
+       when 1 then
+         insert into diagtest_alfa values(1,20,3); -- ok
+       when 2 then
+         insert into diagtest_alfa values(2, null, null);
+       when 3 then
+         insert into diagtest_alfa values(2, 1, null);
+       when 4 then
+         insert into diagtest_alfa values(2, 1, 20);
+       when 5 then
+         insert into diagtest_beta values(1); -- ok
+       when 6 then
+         insert into diagtest_beta values(3);
+       when 7 then
+         delete from diagtest_alfa where id = 1;
+     end case;
+   exception when others then
+     get stacked diagnostics
+       _column_name = COLUMN_NAME,
+       _constraint_name = CONSTRAINT_NAME,
+       _constraint_schema = CONSTRAINT_SCHEMA,
+       _table_name = TABLE_NAME,
+       _schema_name = SCHEMA_NAME;
+   RAISE NOTICE e'column name: %\nconstraint name: %\nconstraint schema: %\ntable name: %\nschema name: %',
+     quote_literal(_column_name),
+     quote_literal(_constraint_name),
+     quote_literal(_constraint_schema),
+     quote_literal(_table_name),
+     quote_literal(_schema_name);
+     raise;
+   end;
+ end;
+ $$ language plpgsql;
+ 
+ select diagtest(1); -- ok
+ select diagtest(1); -- fails - not unique
+ select diagtest(2); -- fails - not null
+ select diagtest(3); -- fails - column's check constraint
+ select diagtest(4); -- fails - table's check constraint
+ select diagtest(5); -- ok
+ select diagtest(6); -- fails FK
+ select diagtest(7); -- fails PK
+ 
+ drop function diagtest(int);
+ 
+ drop table diagtest_beta;
+ drop table diagtest_alfa;
