*** a/doc/src/sgml/config.sgml
--- b/doc/src/sgml/config.sgml
***************
*** 4165,4170 **** CREATE TABLE postgres_log
--- 4165,4180 ----
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)
);
*** a/doc/src/sgml/protocol.sgml
--- b/doc/src/sgml/protocol.sgml
***************
*** 4720,4732 **** message.
The client is responsible for formatting displayed information to meet its
needs; in particular it should break long lines as needed. Newline characters
appearing in the error message fields should be treated as paragraph breaks,
! not line breaks.
--- 4720,4865 ----
+
+
+ c>
+
+
+
+ Column name: the name of the column associated with the the error, if
+ any.
+
+
+
+
+
+
+ t>
+
+
+
+ Table name: the name of the table associated with the error, if any.
+
+
+
+
+
+
+ s>
+
+
+
+ Schema name: the name of schema associated with the error.
+
+
+
+
+
+
+ n>
+
+
+
+ Constraint name: the name of the constraint associated with the error,
+ if any.
+
+
+
+
+
+
+ o>
+
+
+
+ Constraint table: the table name of the constraint associated with the
+ error, if any.
+
+
+
+
+
+
+ m>
+
+
+
+ Constraint schema: the schema name of the constraint associated with the
+ error, if any.
+
+
+
+
+
+
+ r>
+
+
+
+ Routine name: the name of the routine associated with the error, if any.
+
+
+
+
+
+
+ u>
+
+
+
+ Routine schema: the schema of the routine associated with the error, if
+ any.
+
+
+
+
+
+
+ g>
+
+
+
+ Trigger name: the name of the trigger associated with the error, if any.
+
+
+
+
+
+
+ i>
+
+
+
+ Trigger table: the name of the table of the trigger associated with the
+ error, if any.
+
+
+
+
+
+
+ h>
+
+
+
+ Trigger schema: the schema name of the trigger associated with the
+ error, if any.
+
+
+
+
The client is responsible for formatting displayed information to meet its
needs; in particular it should break long lines as needed. Newline characters
appearing in the error message fields should be treated as paragraph breaks,
! not line breaks. Note that certain object names represented as ErrorResponse
! fields, such as Trigger name, are not guaranteed to be unique across a database,
! and such objects cannot generally be uniquely identified by name alone. It may
! be necessary in these cases to unambiguously establish the identity of the
! object of interest based on a unique combination of the object's name, schema
! name, and, in the case of integrity constraints, table name.
*** a/src/backend/access/nbtree/nbtinsert.c
--- b/src/backend/access/nbtree/nbtinsert.c
***************
*** 393,399 **** _bt_check_unique(Relation rel, IndexTuple itup, Relation heapRel,
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)),
! errrel(rel)));
}
}
else if (all_dead)
***************
*** 455,461 **** _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.")));
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."),
! errrel(rel)));
if (nbuf != InvalidBuffer)
_bt_relbuf(rel, nbuf);
***************
*** 533,539 **** _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,
--- 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."),
! errrel(rel)));
/*----------
* If we will need to split the page to put the item on this page,
*** a/src/backend/commands/tablecmds.c
--- b/src/backend/commands/tablecmds.c
***************
*** 3805,3814 **** ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
int attn = lfirst_int(l);
if (heap_attisnull(tuple, attn + 1))
ereport(ERROR,
(errcode(ERRCODE_NOT_NULL_VIOLATION),
errmsg("column \"%s\" contains null values",
! NameStr(newTupDesc->attrs[attn]->attname))));
}
foreach(l, tab->constraints)
--- 3805,3821 ----
int attn = lfirst_int(l);
if (heap_attisnull(tuple, attn + 1))
+ {
+ Form_pg_attribute att = newTupDesc->attrs[attn];
+
ereport(ERROR,
(errcode(ERRCODE_NOT_NULL_VIOLATION),
errmsg("column \"%s\" contains null values",
! NameStr(att->attname)),
! (newrel) ?
! errrelcol(newrel, NameStr(att->attname)) :
! errrelcol(oldrel, NameStr(att->attname))));
! }
}
foreach(l, tab->constraints)
***************
*** 3822,3828 **** ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
ereport(ERROR,
(errcode(ERRCODE_CHECK_VIOLATION),
errmsg("check constraint \"%s\" is violated by some row",
! con->name)));
break;
case CONSTR_FOREIGN:
/* Nothing to do here */
--- 3829,3841 ----
ereport(ERROR,
(errcode(ERRCODE_CHECK_VIOLATION),
errmsg("check constraint \"%s\" is violated by some row",
! con->name),
! (newrel) ?
! errrel(newrel) :
! errrel(oldrel),
! (newrel) ?
! errconstraint(newrel, con->name) :
! errconstraint(oldrel, con->name)));
break;
case CONSTR_FOREIGN:
/* Nothing to do here */
***************
*** 6620,6626 **** validateCheckConstraint(Relation rel, HeapTuple constrtup)
ereport(ERROR,
(errcode(ERRCODE_CHECK_VIOLATION),
errmsg("check constraint \"%s\" is violated by some row",
! NameStr(constrForm->conname))));
ResetExprContext(econtext);
}
--- 6633,6641 ----
ereport(ERROR,
(errcode(ERRCODE_CHECK_VIOLATION),
errmsg("check constraint \"%s\" is violated by some row",
! NameStr(constrForm->conname)),
! errrel(rel),
! errconstraint(rel, NameStr(constrForm->conname))));
ResetExprContext(econtext);
}
*** a/src/backend/commands/typecmds.c
--- b/src/backend/commands/typecmds.c
***************
*** 2233,2245 **** AlterDomainNotNull(List *names, bool notNull)
for (i = 0; i < rtc->natts; i++)
{
int attnum = rtc->atts[i];
if (heap_attisnull(tuple, attnum))
ereport(ERROR,
(errcode(ERRCODE_NOT_NULL_VIOLATION),
errmsg("column \"%s\" of table \"%s\" contains null values",
! NameStr(tupdesc->attrs[attnum - 1]->attname),
! RelationGetRelationName(testrel))));
}
}
heap_endscan(scan);
--- 2233,2246 ----
for (i = 0; i < rtc->natts; i++)
{
int attnum = rtc->atts[i];
+ Form_pg_attribute att = tupdesc->attrs[attnum - 1];
if (heap_attisnull(tuple, attnum))
ereport(ERROR,
(errcode(ERRCODE_NOT_NULL_VIOLATION),
errmsg("column \"%s\" of table \"%s\" contains null values",
! NameStr(att->attname), RelationGetRelationName(testrel)),
! errrelcol(testrel, NameStr(att->attname))));
}
}
heap_endscan(scan);
***************
*** 2608,2614 **** 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))));
}
ResetExprContext(econtext);
--- 2609,2617 ----
(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)),
! errrelcol(testrel,
! NameStr(tupdesc->attrs[attnum - 1]->attname))));
}
ResetExprContext(econtext);
*** a/src/backend/executor/execMain.c
--- b/src/backend/executor/execMain.c
***************
*** 1515,1528 **** ExecConstraints(ResultRelInfo *resultRelInfo,
for (attrChk = 1; attrChk <= natts; attrChk++)
{
if (rel->rd_att->attrs[attrChk - 1]->attnotnull &&
slot_attisnull(slot, attrChk))
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)),
errdetail("Failing row contains %s.",
! ExecBuildSlotValueDescription(slot, 64))));
}
}
--- 1515,1531 ----
for (attrChk = 1; attrChk <= natts; attrChk++)
{
+ Form_pg_attribute Chk = rel->rd_att->attrs[attrChk - 1];
+
if (rel->rd_att->attrs[attrChk - 1]->attnotnull &&
slot_attisnull(slot, attrChk))
ereport(ERROR,
(errcode(ERRCODE_NOT_NULL_VIOLATION),
errmsg("null value in column \"%s\" violates not-null constraint",
! NameStr(Chk->attname)),
errdetail("Failing row contains %s.",
! ExecBuildSlotValueDescription(slot, 64)),
! errrelcol(rel, NameStr(Chk->attname))));
}
}
***************
*** 1536,1542 **** ExecConstraints(ResultRelInfo *resultRelInfo,
errmsg("new row for relation \"%s\" violates check constraint \"%s\"",
RelationGetRelationName(rel), failed),
errdetail("Failing row contains %s.",
! ExecBuildSlotValueDescription(slot, 64))));
}
}
--- 1539,1547 ----
errmsg("new row for relation \"%s\" violates check constraint \"%s\"",
RelationGetRelationName(rel), failed),
errdetail("Failing row contains %s.",
! ExecBuildSlotValueDescription(slot, 64)),
! errrel(rel),
! errconstraint(rel, failed)));
}
}
*** a/src/backend/executor/execUtils.c
--- b/src/backend/executor/execUtils.c
***************
*** 1304,1317 **** retry:
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),
! errrel(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),
! errrel(index)));
}
index_endscan(index_scan);
*** a/src/backend/utils/adt/ri_triggers.c
--- b/src/backend/utils/adt/ri_triggers.c
***************
*** 338,344 **** 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.")));
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."),
! errrel(trigdata->tg_relation),
! errconstraint(trigdata->tg_relation, NameStr(riinfo->conname))));
heap_close(pk_rel, RowShareLock);
return PointerGetDatum(NULL);
***************
*** 2466,2472 **** 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.")));
/*
* 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."),
! errrel(fk_rel),
! errconstraint(fk_rel, NameStr(fake_riinfo.conname))));
!
/*
* We tell ri_ReportViolation we were doing the RI_PLAN_CHECK_LOOKUPPK
***************
*** 3218,3224 **** 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))));
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)),
! errrel(fk_rel),
! errconstraint(fk_rel, NameStr(riinfo->conname))));
else
ereport(ERROR,
(errcode(ERRCODE_FOREIGN_KEY_VIOLATION),
***************
*** 3226,3234 **** ri_ReportViolation(const RI_ConstraintInfo *riinfo,
RelationGetRelationName(pk_rel),
NameStr(riinfo->conname),
RelationGetRelationName(fk_rel)),
! errdetail("Key (%s)=(%s) is still referenced from table \"%s\".",
! key_names.data, key_values.data,
! RelationGetRelationName(fk_rel))));
}
--- 3233,3243 ----
RelationGetRelationName(pk_rel),
NameStr(riinfo->conname),
RelationGetRelationName(fk_rel)),
! errdetail("Key (%s)=(%s) is still referenced from table \"%s\".",
! key_names.data, key_values.data,
! RelationGetRelationName(fk_rel)),
! errrel(pk_rel),
! errconstraint(fk_rel, NameStr(riinfo->conname))));
}
*** a/src/backend/utils/error/Makefile
--- b/src/backend/utils/error/Makefile
***************
*** 12,17 **** subdir = src/backend/utils/error
top_builddir = ../../../..
include $(top_builddir)/src/Makefile.global
! OBJS = assert.o elog.o
include $(top_srcdir)/src/backend/common.mk
--- 12,17 ----
top_builddir = ../../../..
include $(top_builddir)/src/Makefile.global
! OBJS = assert.o elog.o relerror.o
include $(top_srcdir)/src/backend/common.mk
*** a/src/backend/utils/error/elog.c
--- b/src/backend/utils/error/elog.c
***************
*** 131,136 **** static void write_syslog(int level, const char *line);
--- 131,139 ----
static void write_console(const char *line, int len);
+ static void set_errdata_field(char **ptr, const char *str, bool overwrite);
+
+
#ifdef WIN32
extern char *event_source;
static void write_eventlog(int level, const char *line, int len);
***************
*** 477,482 **** errfinish(int dummy,...)
--- 480,507 ----
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,1084 **** internalerrquery(const char *query)
--- 1104,1218 ----
}
/*
+ * err_generic_string -- generic setting of ErrorData string fields
+ */
+ int
+ err_generic_string(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_errdata_field(&edata->message, str, true);
+ break;
+
+ case PG_DIAG_MESSAGE_DETAIL:
+ set_errdata_field(&edata->detail, str, true);
+ break;
+
+ case PG_DIAG_MESSAGE_HINT:
+ set_errdata_field(&edata->hint, str, true);
+ break;
+
+ case PG_DIAG_CONTEXT:
+ set_errdata_field(&edata->context, str, true);
+ break;
+
+ case PG_DIAG_COLUMN_NAME:
+ set_errdata_field(&edata->column_name, str, true);
+ break;
+
+ case PG_DIAG_TABLE_NAME:
+ set_errdata_field(&edata->table_name, str, true);
+ break;
+
+ case PG_DIAG_SCHEMA_NAME:
+ set_errdata_field(&edata->schema_name, str, true);
+ break;
+
+ case PG_DIAG_CONSTRAINT_NAME:
+ set_errdata_field(&edata->constraint_name, str, true);
+ break;
+
+ case PG_DIAG_CONSTRAINT_TABLE:
+ set_errdata_field(&edata->constraint_table, str, true);
+ break;
+
+ case PG_DIAG_CONSTRAINT_SCHEMA:
+ set_errdata_field(&edata->constraint_schema, str, true);
+ break;
+
+ /*
+ * The remaining fields, once set, will not be set again. We need to
+ * guard against resetting here because there is partial redundancy in
+ * the fields set between some of our potential callers, even though two
+ * or more of them might reasonably coexist within the same ereport
+ * call.
+ */
+ case PG_DIAG_ROUTINE_NAME:
+ set_errdata_field(&edata->routine_name, str, false);
+ break;
+
+ case PG_DIAG_ROUTINE_SCHEMA:
+ set_errdata_field(&edata->routine_schema, str, false);
+ break;
+
+ case PG_DIAG_TRIGGER_NAME:
+ set_errdata_field(&edata->trigger_name, str, false);
+ break;
+
+ case PG_DIAG_TRIGGER_TABLE:
+ set_errdata_field(&edata->trigger_table, str, false);
+ break;
+
+ case PG_DIAG_TRIGGER_SCHEMA:
+ set_errdata_field(&edata->trigger_schema, str, false);
+ break;
+
+ default:
+ elog(ERROR, "unknown ErrorData field id %d",
+ field);
+ }
+
+ return 0; /* return value does not matter */
+ }
+
+ /*
+ * set_errdata_field --- set an ErrorData string field, while potentially
+ * avoiding overwriting any existing value
+ */
+ static void
+ set_errdata_field(char **ptr, const char *str, bool overwrite)
+ {
+ if (*ptr != NULL)
+ {
+ /* Avoid overwriting existing value entirely */
+ if (!overwrite)
+ return;
+
+ pfree(*ptr);
+ *ptr = NULL;
+ }
+
+ if (str != NULL)
+ *ptr = MemoryContextStrdup(ErrorContext, str);
+ }
+
+ /*
* geterrcode --- return the currently set SQLSTATE error code
*
* This is only intended for use in error callback subroutines, since there
***************
*** 1352,1357 **** CopyErrorData(void)
--- 1486,1513 ----
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,1382 **** FreeErrorData(ErrorData *edata)
--- 1533,1560 ----
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,1454 **** ReThrowError(ErrorData *edata)
--- 1627,1654 ----
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();
***************
*** 2238,2244 **** write_csvlog(ErrorData *edata)
appendStringInfoChar(&buf, ',');
/* file error location */
- if (Log_error_verbosity >= PGERROR_VERBOSE)
{
StringInfoData msgbuf;
--- 2438,2443 ----
***************
*** 2259,2264 **** write_csvlog(ErrorData *edata)
--- 2458,2507 ----
/* application name */
if (application_name)
appendCSVLiteral(&buf, application_name);
+ appendStringInfoChar(&buf, ',');
+
+ if (Log_error_verbosity >= PGERROR_VERBOSE)
+ appendCSVLiteral(&buf, edata->column_name);
+ appendStringInfoChar(&buf, ',');
+
+ if (Log_error_verbosity >= PGERROR_VERBOSE)
+ appendCSVLiteral(&buf, edata->table_name);
+ appendStringInfoChar(&buf, ',');
+
+ if (Log_error_verbosity >= PGERROR_VERBOSE)
+ appendCSVLiteral(&buf, edata->schema_name);
+ appendStringInfoChar(&buf, ',');
+
+ if (Log_error_verbosity >= PGERROR_VERBOSE)
+ appendCSVLiteral(&buf, edata->constraint_name);
+ appendStringInfoChar(&buf, ',');
+
+ if (Log_error_verbosity >= PGERROR_VERBOSE)
+ appendCSVLiteral(&buf, edata->constraint_table);
+ appendStringInfoChar(&buf, ',');
+
+ if (Log_error_verbosity >= PGERROR_VERBOSE)
+ appendCSVLiteral(&buf, edata->constraint_schema);
+ appendStringInfoChar(&buf, ',');
+
+ if (Log_error_verbosity >= PGERROR_VERBOSE)
+ appendCSVLiteral(&buf, edata->routine_name);
+ appendStringInfoChar(&buf, ',');
+
+ if (Log_error_verbosity >= PGERROR_VERBOSE)
+ appendCSVLiteral(&buf, edata->routine_schema);
+ appendStringInfoChar(&buf, ',');
+
+ if (Log_error_verbosity >= PGERROR_VERBOSE)
+ appendCSVLiteral(&buf, edata->trigger_name);
+ appendStringInfoChar(&buf, ',');
+
+ if (Log_error_verbosity >= PGERROR_VERBOSE)
+ appendCSVLiteral(&buf, edata->trigger_table);
+ appendStringInfoChar(&buf, ',');
+
+ if (Log_error_verbosity >= PGERROR_VERBOSE)
+ appendCSVLiteral(&buf, edata->trigger_schema);
appendStringInfoChar(&buf, '\n');
***************
*** 2377,2382 **** send_message_to_server_log(ErrorData *edata)
--- 2620,2702 ----
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,2678 **** send_message_to_frontend(ErrorData *edata)
--- 2993,3064 ----
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
*** a/src/backend/utils/sort/tuplesort.c
--- b/src/backend/utils/sort/tuplesort.c
***************
*** 3090,3096 **** comparetup_index_btree(const SortTuple *a, const SortTuple *b,
RelationGetRelationName(state->indexRel)),
errdetail("Key %s is duplicated.",
BuildIndexValueDescription(state->indexRel,
! values, isnull))));
}
/*
--- 3090,3097 ----
RelationGetRelationName(state->indexRel)),
errdetail("Key %s is duplicated.",
BuildIndexValueDescription(state->indexRel,
! values, isnull)),
! errrel(state->indexRel)));
}
/*
*** a/src/include/postgres_ext.h
--- b/src/include/postgres_ext.h
***************
*** 55,59 **** typedef unsigned int Oid;
--- 55,70 ----
#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
*** a/src/include/utils/elog.h
--- b/src/include/utils/elog.h
***************
*** 190,195 **** extern int geterrcode(void);
--- 190,197 ----
extern int geterrposition(void);
extern int getinternalerrposition(void);
+ extern int err_generic_string(int field, const char *str);
+
/*----------
* Old-style error reporting API: to be used in this way:
***************
*** 321,330 **** typedef struct ErrorData
char *detail_log; /* detail error message for server log only */
char *hint; /* hint message */
char *context; /* context message */
! int cursorpos; /* cursor index into query string */
! int internalpos; /* cursor index into internalquery */
! char *internalquery; /* text of internally-generated query */
! int saved_errno; /* errno at entry */
} ErrorData;
extern void EmitErrorReport(void);
--- 323,343 ----
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 */
! int saved_errno; /* errno at entry */
} ErrorData;
extern void EmitErrorReport(void);
*** a/src/include/utils/rel.h
--- b/src/include/utils/rel.h
***************
*** 394,397 **** typedef struct StdRdOptions
--- 394,402 ----
extern void RelationIncrementReferenceCount(Relation rel);
extern void RelationDecrementReferenceCount(Relation rel);
+ /* routines in utils/error/relerror.c */
+ extern int errrelcol(Relation rel, const char *colname);
+ extern int errrel(Relation rel);
+ extern int errconstraint(Relation rel, const char *cname);
+
#endif /* REL_H */
*** a/src/interfaces/libpq/fe-protocol3.c
--- b/src/interfaces/libpq/fe-protocol3.c
***************
*** 938,943 **** pqGetErrorNotice3(PGconn *conn, bool isError)
--- 938,988 ----
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);
}
/*