Hello all I am working on new diagnostics fields in errors - CONSTRAINT_NAME, SCHEMA_NAME, TABLE_NAME and COLUMN_NAME.
These fields is shown when verbosity mode is active. Actually this works for table constraints, not null constraint and for RI constraints. postgres=# delete from xxx; ERROR: 23503: update or delete on table "xxx" violates foreign key constraint "yyy_b_fkey" on table "yyy" DETAIL: Key (a)=(10) is still referenced from table "yyy". LOCATION: ri_ReportViolation, ri_triggers.c:3593 CONSTRAINT: yyy_b_fkey SCHEMA: public TABLE: xxx COLUMN: a These fields should be available from GET DIAGNOSTICS statement too - It could be next step after support for stacked diagnostics. I looked on column name identification for column constraints - and there is not any possible identification - so I need a new column to pg_constraint table - "attrid", that should to identify column for column's constraint. This patch is just concept. Final patch will be significantly longer - we need to check any "ereport" call, as this most important constraints are table and ri constraints. Regards Pavel Stehule
*** ./src/backend/executor/execMain.c.orig 2011-06-05 16:09:09.000000000 +0200 --- ./src/backend/executor/execMain.c 2011-06-05 19:46:41.469227198 +0200 *************** *** 1565,1571 **** 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,1575 ---- 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)), ! errconstraintname("not_null_constraint"), ! errschemaname(get_namespace_name(RelationGetNamespace(rel))), ! errtablename(RelationGetRelationName(rel)), ! errcolumnname(NameStr(rel->rd_att->attrs[attrChk - 1]->attname)))); } } *************** *** 1577,1583 **** ereport(ERROR, (errcode(ERRCODE_CHECK_VIOLATION), errmsg("new row for relation \"%s\" violates check constraint \"%s\"", ! RelationGetRelationName(rel), failed))); } } --- 1581,1590 ---- ereport(ERROR, (errcode(ERRCODE_CHECK_VIOLATION), errmsg("new row for relation \"%s\" violates check constraint \"%s\"", ! RelationGetRelationName(rel), failed), ! errconstraintname(failed), ! errschemaname(get_namespace_name(RelationGetNamespace(rel))), ! errtablename(RelationGetRelationName(rel)))); } } *** ./src/backend/utils/adt/ri_triggers.c.orig 2011-06-05 16:09:10.000000000 +0200 --- ./src/backend/utils/adt/ri_triggers.c 2011-06-05 19:57:28.489835680 +0200 *************** *** 3537,3543 **** 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 */ --- 3537,3546 ---- 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)), ! errconstraintname(constrname), ! errschemaname(get_namespace_name(RelationGetNamespace(fk_rel))), ! errtablename(RelationGetRelationName(fk_rel)))); } /* Get printable versions of the keys involved */ *************** *** 3570,3576 **** 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), --- 3573,3583 ---- RelationGetRelationName(fk_rel), constrname), errdetail("Key (%s)=(%s) is not present in table \"%s\".", key_names.data, key_values.data, ! RelationGetRelationName(pk_rel)), ! errconstraintname(constrname), ! errschemaname(get_namespace_name(RelationGetNamespace(fk_rel))), ! errtablename(RelationGetRelationName(fk_rel)), ! errcolumnname(key_names.data))); else ereport(ERROR, (errcode(ERRCODE_FOREIGN_KEY_VIOLATION), *************** *** 3579,3585 **** constrname, RelationGetRelationName(fk_rel)), errdetail("Key (%s)=(%s) is still referenced from table \"%s\".", key_names.data, key_values.data, ! RelationGetRelationName(fk_rel)))); } /* ---------- --- 3586,3596 ---- constrname, RelationGetRelationName(fk_rel)), errdetail("Key (%s)=(%s) is still referenced from table \"%s\".", key_names.data, key_values.data, ! RelationGetRelationName(fk_rel)), ! errconstraintname(constrname), ! errschemaname(get_namespace_name(RelationGetNamespace(pk_rel))), ! errtablename(RelationGetRelationName(pk_rel)), ! errcolumnname(key_names.data))); } /* ---------- *** ./src/backend/utils/error/elog.c.orig 2011-06-05 16:09:10.000000000 +0200 --- ./src/backend/utils/error/elog.c 2011-06-05 18:38:15.780832408 +0200 *************** *** 989,994 **** --- 989,1089 ---- } /* + * errconstraintname - add name of constraint related to current error + */ + int + errconstraintname(const char *constraint_name) + { + ErrorData *edata = &errordata[errordata_stack_depth]; + + /* we don't bother incrementing recursion_depth */ + CHECK_STACK_DEPTH(); + + if (edata->constraint_name) + { + pfree(edata->constraint_name); + edata->constraint_name = NULL; + } + + if (constraint_name) + edata->constraint_name = MemoryContextStrdup(ErrorContext, constraint_name); + + return 0; /* return value does not matter */ + } + + + + /* + * errschemaname - add name of schema related to current error + */ + int + errschemaname(const char *schema_name) + { + ErrorData *edata = &errordata[errordata_stack_depth]; + + /* we don't bother incrementing recursion_depth */ + CHECK_STACK_DEPTH(); + + if (edata->schema_name) + { + pfree(edata->schema_name); + edata->schema_name = NULL; + } + + if (schema_name) + edata->schema_name = MemoryContextStrdup(ErrorContext, schema_name); + + return 0; /* return value does not matter */ + } + + /* + * errtablename - add name of table related to current error + */ + int + errtablename(const char *table_name) + { + ErrorData *edata = &errordata[errordata_stack_depth]; + + /* we don't bother incrementing recursion_depth */ + CHECK_STACK_DEPTH(); + + if (edata->table_name) + { + pfree(edata->table_name); + edata->table_name = NULL; + } + + if (table_name) + edata->table_name = MemoryContextStrdup(ErrorContext, table_name); + + return 0; /* return value does not matter */ + } + + /* + * errcolumnname - add name of column related to current error + */ + int + errcolumnname(const char *column_name) + { + ErrorData *edata = &errordata[errordata_stack_depth]; + + /* we don't bother incrementing recursion_depth */ + CHECK_STACK_DEPTH(); + + if (edata->column_name) + { + pfree(edata->column_name); + edata->column_name = NULL; + } + + if (column_name) + edata->column_name = MemoryContextStrdup(ErrorContext, column_name); + + return 0; /* return value does not matter */ + } + + + /* * internalerrposition --- add internal cursor position to the current error */ int *************** *** 1277,1282 **** --- 1372,1385 ---- newedata->hint = pstrdup(newedata->hint); if (newedata->context) newedata->context = pstrdup(newedata->context); + if (newedata->constraint_name) + newedata->constraint_name = pstrdup(newedata->constraint_name); + if (newedata->schema_name) + newedata->schema_name = pstrdup(newedata->schema_name); + if (newedata->table_name) + newedata->table_name = pstrdup(newedata->table_name); + if (newedata->column_name) + newedata->column_name = pstrdup(newedata->column_name); if (newedata->internalquery) newedata->internalquery = pstrdup(newedata->internalquery); *************** *** 1304,1309 **** --- 1407,1421 ---- pfree(edata->context); if (edata->internalquery) pfree(edata->internalquery); + if (edata->constraint_name) + pfree(edata->constraint_name); + if (edata->schema_name) + pfree(edata->schema_name); + if (edata->table_name) + pfree(edata->table_name); + if (edata->column_name) + pfree(edata->column_name); + pfree(edata); } *************** *** 1374,1379 **** --- 1486,1499 ---- newedata->hint = pstrdup(newedata->hint); if (newedata->context) newedata->context = pstrdup(newedata->context); + if (newedata->constraint_name) + newedata->constraint_name = pstrdup(newedata->constraint_name); + if (newedata->schema_name) + newedata->schema_name = pstrdup(newedata->schema_name); + if (newedata->table_name) + newedata->table_name = pstrdup(newedata->table_name); + if (newedata->column_name) + newedata->column_name = pstrdup(newedata->column_name); if (newedata->internalquery) newedata->internalquery = pstrdup(newedata->internalquery); *************** *** 2197,2202 **** --- 2317,2337 ---- if (application_name) appendCSVLiteral(&buf, application_name); + /* constraint_name */ + appendCSVLiteral(&buf, edata->constraint_name); + appendStringInfoChar(&buf, ','); + + /* schema name */ + appendCSVLiteral(&buf, edata->schema_name); + appendStringInfoChar(&buf, ','); + + /* table name */ + appendCSVLiteral(&buf, edata->table_name); + appendStringInfoChar(&buf, ','); + + /* column name */ + appendCSVLiteral(&buf, edata->column_name); + appendStringInfoChar(&buf, '\n'); /* If in the syslogger process, try to write messages direct to file */ *************** *** 2284,2289 **** --- 2419,2452 ---- append_with_tabs(&buf, edata->hint); appendStringInfoChar(&buf, '\n'); } + if (edata->constraint_name) + { + log_line_prefix(&buf, edata); + appendStringInfoString(&buf, _("CONSTRAINT: ")); + append_with_tabs(&buf, edata->constraint_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->table_name) + { + log_line_prefix(&buf, edata); + appendStringInfoString(&buf, _("TABLE: ")); + append_with_tabs(&buf, edata->table_name); + appendStringInfoChar(&buf, '\n'); + } + if (edata->column_name) + { + log_line_prefix(&buf, edata); + appendStringInfoString(&buf, _("COLUMN: ")); + append_with_tabs(&buf, edata->column_name); + appendStringInfoChar(&buf, '\n'); + } if (edata->internalquery) { log_line_prefix(&buf, edata); *************** *** 2552,2557 **** --- 2715,2744 ---- err_sendstring(&msgbuf, edata->context); } + if (edata->constraint_name) + { + pq_sendbyte(&msgbuf, PG_DIAG_CONSTRAINT_NAME); + err_sendstring(&msgbuf, edata->constraint_name); + } + + if (edata->schema_name) + { + pq_sendbyte(&msgbuf, PG_DIAG_SCHEMA_NAME); + err_sendstring(&msgbuf, edata->schema_name); + } + + if (edata->table_name) + { + pq_sendbyte(&msgbuf, PG_DIAG_TABLE_NAME); + err_sendstring(&msgbuf, edata->table_name); + } + + if (edata->column_name) + { + pq_sendbyte(&msgbuf, PG_DIAG_COLUMN_NAME); + err_sendstring(&msgbuf, edata->column_name); + } + if (edata->cursorpos > 0) { snprintf(tbuf, sizeof(tbuf), "%d", edata->cursorpos); *** ./src/include/postgres_ext.h.orig 2011-06-05 16:09:10.000000000 +0200 --- ./src/include/postgres_ext.h 2011-06-05 18:31:35.428844302 +0200 *************** *** 55,59 **** #define PG_DIAG_SOURCE_FILE 'F' #define PG_DIAG_SOURCE_LINE 'L' #define PG_DIAG_SOURCE_FUNCTION 'R' ! #endif --- 55,62 ---- #define PG_DIAG_SOURCE_FILE 'F' #define PG_DIAG_SOURCE_LINE 'L' #define PG_DIAG_SOURCE_FUNCTION 'R' ! #define PG_DIAG_SCHEMA_NAME 's' ! #define PG_DIAG_TABLE_NAME 't' ! #define PG_DIAG_COLUMN_NAME 'c' ! #define PG_DIAG_CONSTRAINT_NAME 'n' #endif *** ./src/include/utils/elog.h.orig 2011-06-05 16:09:10.000000000 +0200 --- ./src/include/utils/elog.h 2011-06-05 18:30:39.938499613 +0200 *************** *** 177,182 **** --- 177,187 ---- extern int errfunction(const char *funcname); extern int errposition(int cursorpos); + extern int errconstraintname(const char *constraint_name); + extern int errschemaname(const char *schema_name); + extern int errtablename(const char *table_name); + extern int errcolumnname(const char *column_name); + extern int internalerrposition(int cursorpos); extern int internalerrquery(const char *query); *************** *** 315,320 **** --- 320,329 ---- char *detail_log; /* detail error message for server log only */ char *hint; /* hint message */ char *context; /* context message */ + char *constraint_name; /* name of constraint related to error */ + char *schema_name; /* name of schema that contains table related to error */ + char *table_name; /* name of table related to error */ + char *column_name; /* name of column related to error */ int cursorpos; /* cursor index into query string */ int internalpos; /* cursor index into internalquery */ char *internalquery; /* text of internally-generated query */ *** ./src/interfaces/libpq/fe-protocol3.c.orig 2011-06-05 16:09:10.000000000 +0200 --- ./src/interfaces/libpq/fe-protocol3.c 2011-06-05 18:32:38.101139497 +0200 *************** *** 856,861 **** --- 856,873 ---- valf, vall); appendPQExpBufferChar(&workBuf, '\n'); } + val = PQresultErrorField(res, PG_DIAG_CONSTRAINT_NAME); + if (val) + appendPQExpBuffer(&workBuf, libpq_gettext("CONSTRAINT: %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_TABLE_NAME); + if (val) + appendPQExpBuffer(&workBuf, libpq_gettext("TABLE: %s\n"), val); + val = PQresultErrorField(res, PG_DIAG_COLUMN_NAME); + if (val) + appendPQExpBuffer(&workBuf, libpq_gettext("COLUMN: %s\n"), val); } /*
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers