Hello I am sending a updated patch
> > Coding Review > ----------------- > > > In tupdesc.c > > line 202 the existing code is performing a deep copy of ConstrCheck. Do you > need to copy nkeys and conkey here as well? > > Then at line 250 ccname is freed but not conkey > fixed > > postgres_ext.h line 55 > + #define PG_DIAG_SCHEMA_NAME 's' > + #define PG_DIAG_TABLE_NAME 't' > + #define PG_DIAG_COLUMN_NAMES 'c' > + #define PG_DIAG_CONSTRAINT_NAME 'n' > > The assignment of letters to parameters seems arbitrary to me, I don't have > a different non-arbitrary mapping in mind but if anyone else does they > should speak up. I think it will be difficult to change this after 9.2 goes > out. > > > elog.c: > *************** > *** 2197,2202 **** > --- 2299,2319 ---- > 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, ','); > > You need to update config.sgml at the same time you update this format. > You need to append a "," after application name but before constraintName. > As it stands the CSV log has something like: > .....nbtinsert.c:433","psql""a_pkey","public","a","a" fixed > > > nbtinsert.c > > pg_get_indrelation is named differently than everything else in this file > (ie _bt...). My guess is that this function belongs somewhere else but I > don't know the code well enough to say where you should move it too. > I renamed this function to IndexRelationGetParentRelation and muved to relcache.c I don't call a quote_identifier on only data error properties like table_name or schema_name (but I am open to arguments for it or against it). The quote_identifier is used for column names, because there should be a more names and comma should be used inside name - and this is consistent with pg_get_indexdef_columns. Regards Pavel Stehule
*** ./doc/src/sgml/config.sgml.orig 2011-06-20 18:08:39.000000000 +0200 --- ./doc/src/sgml/config.sgml 2011-06-20 21:12:31.688165497 +0200 *************** *** 3919,3927 **** user query that led to the error (if any and enabled by <varname>log_min_error_statement</>), character count of the error position therein, ! location of the error in the PostgreSQL source code (if <varname>log_error_verbosity</> is set to <literal>verbose</>), ! and application name. Here is a sample table definition for storing CSV-format log output: <programlisting> --- 3919,3933 ---- user query that led to the error (if any and enabled by <varname>log_min_error_statement</>), character count of the error position therein, ! location of the error in the PostgreSQL source code, (if <varname>log_error_verbosity</> is set to <literal>verbose</>), ! application name, ! (following fields to end are filled when <varname>log_error_verbosity</> is ! set to <literal>verbose</>) ! constraint name, ! schema name, ! table name, ! and column names. Here is a sample table definition for storing CSV-format log output: <programlisting> *************** *** 3950,3955 **** --- 3956,3965 ---- query_pos integer, location text, application_name text, + constraint_name text, + schema_name text, + table_name text, + column_names text, PRIMARY KEY (session_id, session_line_num) ); </programlisting> *** ./src/backend/access/common/tupdesc.c.orig 2011-06-20 18:08:39.000000000 +0200 --- ./src/backend/access/common/tupdesc.c 2011-06-20 20:30:15.477883102 +0200 *************** *** 200,205 **** --- 200,217 ---- cpy->check[i].ccname = pstrdup(constr->check[i].ccname); if (constr->check[i].ccbin) cpy->check[i].ccbin = pstrdup(constr->check[i].ccbin); + if (constr->check[i].nkeys > 0) + { + cpy->check[i].conkey = palloc(sizeof(int16) * constr->check[i].nkeys); + memcpy(cpy->check[i].conkey, constr->check[i].conkey, + sizeof(int16) * constr->check[i].nkeys); + cpy->check[i].nkeys = constr->check[i].nkeys; + } + else + { + cpy->check[i].conkey = NULL; + constr->check[i].nkeys = 0; + } } } *************** *** 249,254 **** --- 261,268 ---- pfree(check[i].ccname); if (check[i].ccbin) pfree(check[i].ccbin); + if (check[i].conkey) + pfree(check[i].conkey); } pfree(check); } *************** *** 409,414 **** --- 423,431 ---- * Similarly, don't assume that the checks are always read in the * same order; match them up by name and contents. (The name * *should* be unique, but...) + * + * nkeys and conkey depends on ccbin, and there are not neccessary + * to compare it. */ for (j = 0; j < n; check2++, j++) { *** ./src/backend/access/nbtree/nbtinsert.c.orig 2011-06-20 18:08:39.000000000 +0200 --- ./src/backend/access/nbtree/nbtinsert.c 2011-06-20 20:50:45.067330278 +0200 *************** *** 23,29 **** --- 23,31 ---- #include "storage/lmgr.h" #include "storage/predicate.h" #include "utils/inval.h" + #include "utils/builtins.h" #include "utils/tqual.h" + #include "utils/relcache.h" typedef struct *************** *** 394,400 **** RelationGetRelationName(rel)), errdetail("Key %s already exists.", BuildIndexValueDescription(rel, ! values, isnull)))); } } else if (all_dead) --- 396,405 ---- RelationGetRelationName(rel)), errdetail("Key %s already exists.", BuildIndexValueDescription(rel, ! values, isnull)), ! errconstrname(RelationGetRelationName(rel)), ! errrel(IndexRelationGetParentRelation(rel)), ! errcolnames(pg_get_indexdef_columns(RelationGetRelid(rel), true)))); } } else if (all_dead) *************** *** 534,540 **** 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,548 ---- 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."), ! errconstrname(RelationGetRelationName(rel)), ! errrel(IndexRelationGetParentRelation(rel)), ! errcolnames(pg_get_indexdef_columns(RelationGetRelid(rel), true)))); /*---------- * If we will need to split the page to put the item on this page, *** ./src/backend/executor/execMain.c.orig 2011-06-20 18:08:39.117098297 +0200 --- ./src/backend/executor/execMain.c 2011-06-20 21:35:58.047263844 +0200 *************** *** 57,62 **** --- 57,63 ---- #include "storage/smgr.h" #include "tcop/utility.h" #include "utils/acl.h" + #include "utils/builtins.h" #include "utils/lsyscache.h" #include "utils/memutils.h" #include "utils/snapmgr.h" *************** *** 1485,1491 **** /* * ExecRelCheck --- check that tuple meets constraints for result relation */ ! static const char * ExecRelCheck(ResultRelInfo *resultRelInfo, TupleTableSlot *slot, EState *estate) { --- 1486,1492 ---- /* * ExecRelCheck --- check that tuple meets constraints for result relation */ ! static ConstrCheck * ExecRelCheck(ResultRelInfo *resultRelInfo, TupleTableSlot *slot, EState *estate) { *************** *** 1537,1543 **** * ExecQual to return TRUE for NULL. */ if (!ExecQual(qual, econtext, true)) ! return check[i].ccname; } /* NULL result means no error */ --- 1538,1544 ---- * ExecQual to return TRUE for NULL. */ if (!ExecQual(qual, econtext, true)) ! return &check[i]; } /* NULL result means no error */ *************** *** 1565,1583 **** 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)))); } } if (constr->num_check > 0) { ! const char *failed; if ((failed = ExecRelCheck(resultRelInfo, slot, estate)) != NULL) ereport(ERROR, (errcode(ERRCODE_CHECK_VIOLATION), errmsg("new row for relation \"%s\" violates check constraint \"%s\"", ! RelationGetRelationName(rel), failed))); } } --- 1566,1605 ---- 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)), ! errconstrname("not_null_constraint"), ! errrel(rel), ! errcolnames(quote_identifier(NameStr(rel->rd_att->attrs[attrChk - 1]->attname))))); } } if (constr->num_check > 0) { ! ConstrCheck *failed; if ((failed = ExecRelCheck(resultRelInfo, slot, estate)) != NULL) + { + StringInfoData names; + int idx; + + /* Get a column names specified by conkey array */ + initStringInfo(&names); + for (idx = 0; idx < failed->nkeys; idx++) + { + if (idx > 0) + appendStringInfoString(&names, ", "); + appendStringInfoString(&names, quote_identifier(NameStr(rel->rd_att->attrs[failed->conkey[idx] - 1]->attname))); + } + ereport(ERROR, (errcode(ERRCODE_CHECK_VIOLATION), errmsg("new row for relation \"%s\" violates check constraint \"%s\"", ! RelationGetRelationName(rel), failed->ccname), ! errconstrname(failed->ccname), ! errrel(rel), ! errcolnames(names.data))); ! pfree(names.data); ! } } } *** ./src/backend/executor/execUtils.c.orig 2011-06-20 18:08:39.000000000 +0200 --- ./src/backend/executor/execUtils.c 2011-06-20 20:59:42.740717038 +0200 *************** *** 44,49 **** --- 44,50 ---- #include "access/genam.h" #include "access/heapam.h" + #include "access/nbtree.h" #include "access/relscan.h" #include "access/transam.h" #include "catalog/index.h" *************** *** 51,56 **** --- 52,58 ---- #include "nodes/nodeFuncs.h" #include "parser/parsetree.h" #include "storage/lmgr.h" + #include "utils/builtins.h" #include "utils/memutils.h" #include "utils/relcache.h" #include "utils/tqual.h" *************** *** 1304,1317 **** errmsg("could not create exclusion constraint \"%s\"", RelationGetRelationName(index)), errdetail("Key %s conflicts with key %s.", ! error_new, error_existing))); else ereport(ERROR, (errcode(ERRCODE_EXCLUSION_VIOLATION), errmsg("conflicting key value violates exclusion constraint \"%s\"", RelationGetRelationName(index)), errdetail("Key %s conflicts with existing key %s.", ! error_new, error_existing))); } index_endscan(index_scan); --- 1306,1325 ---- errmsg("could not create exclusion constraint \"%s\"", RelationGetRelationName(index)), errdetail("Key %s conflicts with key %s.", ! error_new, error_existing), ! errconstrname(RelationGetRelationName(index)), ! errrel(IndexRelationGetParentRelation(index)), ! errcolnames(pg_get_indexdef_columns(RelationGetRelid(index), true)))); 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), ! errconstrname(RelationGetRelationName(index)), ! errrel(IndexRelationGetParentRelation(index)), ! errcolnames(pg_get_indexdef_columns(RelationGetRelid(index), true)))); } index_endscan(index_scan); *** ./src/backend/utils/adt/ri_triggers.c.orig 2011-06-20 18:08:39.000000000 +0200 --- ./src/backend/utils/adt/ri_triggers.c 2011-06-20 20:53:25.261955709 +0200 *************** *** 2839,2845 **** 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."))); } /* --- 2839,2847 ---- 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."), ! errconstrname(constrname), ! errrel(fk_rel))); } /* *************** *** 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 */ --- 3539,3547 ---- 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)), ! errconstrname(constrname), ! errrel(fk_rel))); } /* Get printable versions of the keys involved */ *************** *** 3570,3585 **** 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), errmsg("update or delete on table \"%s\" violates foreign key constraint \"%s\" on table \"%s\"", RelationGetRelationName(pk_rel), constrname, RelationGetRelationName(fk_rel)), ! errdetail("Key (%s)=(%s) is still referenced from table \"%s\".", key_names.data, key_values.data, ! RelationGetRelationName(fk_rel)))); } /* ---------- --- 3574,3595 ---- RelationGetRelationName(fk_rel), constrname), errdetail("Key (%s)=(%s) is not present in table \"%s\".", key_names.data, key_values.data, ! RelationGetRelationName(pk_rel)), ! errconstrname(constrname), ! errrel(fk_rel), ! errcolnames(key_names.data))); else ereport(ERROR, (errcode(ERRCODE_FOREIGN_KEY_VIOLATION), errmsg("update or delete on table \"%s\" violates foreign key constraint \"%s\" on table \"%s\"", RelationGetRelationName(pk_rel), constrname, RelationGetRelationName(fk_rel)), ! errdetail("Key (%s)=(%s) is still referenced from table \"%s\".", key_names.data, key_values.data, ! RelationGetRelationName(fk_rel)), ! errconstrname(constrname), ! errrel(pk_rel), ! errcolnames(key_names.data))); } /* ---------- *** ./src/backend/utils/cache/relcache.c.orig 2011-06-20 18:52:45.894162522 +0200 --- ./src/backend/utils/cache/relcache.c 2011-06-20 20:32:45.254598114 +0200 *************** *** 3264,3269 **** --- 3264,3303 ---- check[found].ccbin = MemoryContextStrdup(CacheMemoryContext, TextDatumGetCString(val)); + /* + * We should to load a conkey column. This numbers will be translated + * to column names available via PG_COLUMN_NAMES property for GET STACKED + * DIAGNOSTICS statement. + */ + val = fastgetattr(htup, + Anum_pg_constraint_conkey, + conrel->rd_att, &isnull); + if (!isnull) + { + ArrayType *arr; + int numkeys; + + arr = DatumGetArrayTypeP(val); /* ensure not toasted */ + numkeys = ARR_DIMS(arr)[0]; + if (ARR_NDIM(arr) != 1 || + numkeys < 0 || + ARR_HASNULL(arr) || + ARR_ELEMTYPE(arr) != INT2OID) + + elog(ERROR, "conkey is not a 1-D smallint array"); + check[found].nkeys = numkeys; + check[found].conkey = MemoryContextAlloc(CacheMemoryContext, + numkeys * sizeof(int16)); + memcpy(check[found].conkey, ARR_DATA_PTR(arr), numkeys * sizeof(int16)); + + if ((Pointer) arr != DatumGetPointer(val)) + pfree(arr); /* free de-toasted copy, if any */ + } + else + { + check[found].nkeys = 0; + check[found].conkey = NULL; + } found++; } *************** *** 4584,4586 **** --- 4618,4651 ---- elog(LOG, "could not remove cache file \"%s\": %m", initfilename); } } + + /* + * Returns a parent relation of index relation + */ + Relation + IndexRelationGetParentRelation(Relation indexRelation) + { + HeapTuple ht_idx; + Form_pg_index idxrec; + Oid indrelid; + Relation r; + + /* + * Fetch the pg_index tuple by the Oid of the index + */ + ht_idx = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(RelationGetRelid(indexRelation))); + if (!HeapTupleIsValid(ht_idx)) + elog(ERROR, "cache lookup failed for index %u", RelationGetRelid(indexRelation)); + idxrec = (Form_pg_index) GETSTRUCT(ht_idx); + + indrelid = idxrec->indrelid; + r = RelationIdGetRelation(indrelid); + + if (!RelationIsValid(r)) + elog(ERROR, "could not open relation with OID %u", indrelid); + + /* Clean up */ + ReleaseSysCache(ht_idx); + + return r; + } *** ./src/backend/utils/error/elog.c.orig 2011-06-20 18:08:39.000000000 +0200 --- ./src/backend/utils/error/elog.c 2011-06-20 20:13:52.818261185 +0200 *************** *** 75,82 **** --- 75,84 ---- #include "storage/proc.h" #include "tcop/tcopprot.h" #include "utils/guc.h" + #include "utils/lsyscache.h" #include "utils/memutils.h" #include "utils/ps_status.h" + #include "utils/relcache.h" #undef _ *************** *** 972,977 **** --- 974,1056 ---- return 0; /* return value does not matter */ } + /* + * errconstraintname - add name of constraint related to current error + */ + int + errconstrname(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 */ + } + + /* + * errrel - add a schema name and table name of table related to current error + */ + int + errrel(Relation rel) + { + ErrorData *edata = &errordata[errordata_stack_depth]; + MemoryContext oldcontext; + + /* we don't bother incrementing recursion_depth */ + CHECK_STACK_DEPTH(); + + if (edata->schema_name) + pfree(edata->schema_name); + + if (edata->table_name) + pfree(edata->table_name); + + oldcontext = MemoryContextSwitchTo(ErrorContext); + + edata->schema_name = get_namespace_name(RelationGetNamespace(rel)); + edata->table_name = pstrdup(RelationGetRelationName(rel)); + + MemoryContextSwitchTo(oldcontext); + + return 0; /* return value does not matter */ + } + + + /* + * errcolnames - add names of columns related to current error + */ + int + errcolnames(const char *column_names) + { + ErrorData *edata = &errordata[errordata_stack_depth]; + + /* we don't bother incrementing recursion_depth */ + CHECK_STACK_DEPTH(); + + if (edata->column_names) + { + pfree(edata->column_names); + edata->column_names = NULL; + } + + if (column_names) + edata->column_names = MemoryContextStrdup(ErrorContext, column_names); + + return 0; /* return value does not matter */ + } + + + /* * errposition --- add cursor position to the current error */ *************** *** 1277,1282 **** --- 1356,1369 ---- 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_names) + newedata->column_names = pstrdup(newedata->column_names); if (newedata->internalquery) newedata->internalquery = pstrdup(newedata->internalquery); *************** *** 1302,1307 **** --- 1389,1402 ---- pfree(edata->hint); if (edata->context) pfree(edata->context); + 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_names) + pfree(edata->column_names); if (edata->internalquery) pfree(edata->internalquery); pfree(edata); *************** *** 1374,1379 **** --- 1469,1482 ---- 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_names) + newedata->column_names = pstrdup(newedata->column_names); if (newedata->internalquery) newedata->internalquery = pstrdup(newedata->internalquery); *************** *** 2196,2201 **** --- 2299,2324 ---- /* application name */ if (application_name) appendCSVLiteral(&buf, application_name); + appendStringInfoChar(&buf, ','); + + /* constraint_name */ + if (edata->constraint_name && Log_error_verbosity >= PGERROR_VERBOSE) + appendCSVLiteral(&buf, edata->constraint_name); + appendStringInfoChar(&buf, ','); + + /* schema name */ + if (edata->schema_name && Log_error_verbosity >= PGERROR_VERBOSE) + appendCSVLiteral(&buf, edata->schema_name); + appendStringInfoChar(&buf, ','); + + /* table name */ + if (edata->table_name && Log_error_verbosity >= PGERROR_VERBOSE) + appendCSVLiteral(&buf, edata->table_name); + appendStringInfoChar(&buf, ','); + + /* column names */ + if (edata->column_names && Log_error_verbosity >= PGERROR_VERBOSE) + appendCSVLiteral(&buf, edata->column_names); appendStringInfoChar(&buf, '\n'); *************** *** 2314,2319 **** --- 2437,2471 ---- appendStringInfo(&buf, _("LOCATION: %s:%d\n"), edata->filename, edata->lineno); } + + 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_names) + { + log_line_prefix(&buf, edata); + appendStringInfoString(&buf, _("COLUMN: ")); + append_with_tabs(&buf, edata->column_names); + appendStringInfoChar(&buf, '\n'); + } } } *************** *** 2552,2557 **** --- 2704,2733 ---- 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_names) + { + pq_sendbyte(&msgbuf, PG_DIAG_COLUMN_NAMES); + err_sendstring(&msgbuf, edata->column_names); + } + if (edata->cursorpos > 0) { snprintf(tbuf, sizeof(tbuf), "%d", edata->cursorpos); *** ./src/include/access/tupdesc.h.orig 2011-06-20 19:45:49.000000000 +0200 --- ./src/include/access/tupdesc.h 2011-06-20 19:49:26.854819079 +0200 *************** *** 29,34 **** --- 29,36 ---- { char *ccname; char *ccbin; /* nodeToString representation of expr */ + int16 nkeys; /* numbers of columns related to constraint */ + int16 *conkey; /* array numbers of columns related to constraint */ } ConstrCheck; /* This structure contains constraints of a tuple */ *** ./src/include/postgres_ext.h.orig 2011-06-20 19:45:49.000000000 +0200 --- ./src/include/postgres_ext.h 2011-06-20 19:49:26.854819079 +0200 *************** *** 55,59 **** --- 55,63 ---- #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_NAMES 'c' + #define PG_DIAG_CONSTRAINT_NAME 'n' #endif *** ./src/include/utils/elog.h.orig 2011-06-20 18:08:39.000000000 +0200 --- ./src/include/utils/elog.h 2011-06-20 19:49:26.855819068 +0200 *************** *** 15,20 **** --- 15,21 ---- #define ELOG_H #include <setjmp.h> + #include "utils/relcache.h" /* Error level codes */ #define DEBUG5 10 /* Debugging messages, in categories of *************** *** 177,182 **** --- 178,187 ---- extern int errfunction(const char *funcname); extern int errposition(int cursorpos); + extern int errconstrname(const char *constraint_name); + extern int errrel(Relation rel); + extern int errcolnames(const char *column_names); + 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; /* schema of table related to error */ + char *table_name; /* name of table related to error */ + char *column_names; /* names of columns related to error */ int cursorpos; /* cursor index into query string */ int internalpos; /* cursor index into internalquery */ char *internalquery; /* text of internally-generated query */ *** ./src/include/utils/relcache.h.orig 2011-06-20 18:08:39.000000000 +0200 --- ./src/include/utils/relcache.h 2011-06-20 18:55:00.718993324 +0200 *************** *** 53,58 **** --- 53,60 ---- extern void RelationInitIndexAccessInfo(Relation relation); + extern Relation IndexRelationGetParentRelation(Relation indexRelation); + /* * Routines for backend startup */ *** ./src/interfaces/libpq/fe-protocol3.c.orig 2011-06-20 19:45:49.000000000 +0200 --- ./src/interfaces/libpq/fe-protocol3.c 2011-06-20 19:49:26.856819058 +0200 *************** *** 856,861 **** --- 856,874 ---- 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_NAMES); + if (val) + appendPQExpBuffer(&workBuf, libpq_gettext("COLUMNS: %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