Hello
Attached patch implements a new erros's fields that describes table,
colums related to error. This enhanced info is limited to constraints
and RI.
example:
postgres=# create table omega(a int unique not null check (a > 10));
NOTICE: 00000: CREATE TABLE / UNIQUE will create implicit index
"omega_a_key" for table "omega"
LOCATION: DefineIndex, indexcmds.c:389
CREATE TABLE
Time: 106.867 ms
postgres=# \set VERBOSITY verbose
postgres=# insert into omega values(0);
ERROR: 23514: new row for relation "omega" violates check constraint
"omega_a_check"
LOCATION: ExecConstraints, execMain.c:1547
CONSTRAINT: omega_a_check
SCHEMA: public
TABLE: omega
COLUMNS: a
postgres=# insert into omega values(null);
ERROR: 23502: null value in column "a" violates not-null constraint
LOCATION: ExecConstraints, execMain.c:1519
CONSTRAINT: not_null_constraint
SCHEMA: public
TABLE: omega
COLUMNS: a
postgres=# insert into omega values(20);
INSERT 0 1
Time: 60.588 ms
postgres=# insert into omega values(20);
ERROR: 23505: duplicate key value violates unique constraint "omega_a_key"
DETAIL: Key (a)=(20) already exists.
LOCATION: _bt_check_unique, nbtinsert.c:432
CONSTRAINT: omega_a_key
SCHEMA: public
TABLE: omega
COLUMNS: a
postgres=#
This is base for support variables CONSTRAINT_NAME, SCHEMA_NAME and
TABLE_NAME for GET DIAGNOSTICS statement.
All regress tests was successfully passed
Regards
Pavel Stehule
*** ./src/backend/access/nbtree/nbtinsert.c.orig 2011-04-27 23:17:22.000000000 +0200
--- ./src/backend/access/nbtree/nbtinsert.c 2011-06-08 21:57:45.616691664 +0200
***************
*** 23,28 ****
--- 23,30 ----
#include "storage/lmgr.h"
#include "storage/predicate.h"
#include "utils/inval.h"
+ #include "utils/builtins.h"
+ #include "utils/syscache.h"
#include "utils/tqual.h"
***************
*** 83,88 ****
--- 85,121 ----
/*
+ * Returns a parent relation of index
+ */
+ Relation
+ pg_get_indrelation(Relation idxrel)
+ {
+ 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(idxrel)));
+ if (!HeapTupleIsValid(ht_idx))
+ elog(ERROR, "cache lookup failed for index %u", RelationGetRelid(idxrel));
+ 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;
+ }
+
+ /*
* _bt_doinsert() -- Handle insertion of a single index tuple in the tree.
*
* This routine is called by the public interface routines, btbuild
***************
*** 394,400 ****
RelationGetRelationName(rel)),
errdetail("Key %s already exists.",
BuildIndexValueDescription(rel,
! values, isnull))));
}
}
else if (all_dead)
--- 427,436 ----
RelationGetRelationName(rel)),
errdetail("Key %s already exists.",
BuildIndexValueDescription(rel,
! values, isnull)),
! errconstrname(RelationGetRelationName(rel)),
! errrel(pg_get_indrelation(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,
--- 570,578 ----
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(pg_get_indrelation(rel))));
/*----------
* If we will need to split the page to put the item on this page,
*** ./src/backend/executor/execMain.c.orig 2011-04-27 23:17:22.000000000 +0200
--- ./src/backend/executor/execMain.c 2011-06-08 18:51:19.492670762 +0200
***************
*** 1433,1439 ****
/*
* ExecRelCheck --- check that tuple meets constraints for result relation
*/
! static const char *
ExecRelCheck(ResultRelInfo *resultRelInfo,
TupleTableSlot *slot, EState *estate)
{
--- 1433,1439 ----
/*
* ExecRelCheck --- check that tuple meets constraints for result relation
*/
! static ConstrCheck *
ExecRelCheck(ResultRelInfo *resultRelInfo,
TupleTableSlot *slot, EState *estate)
{
***************
*** 1485,1491 ****
* ExecQual to return TRUE for NULL.
*/
if (!ExecQual(qual, econtext, true))
! return check[i].ccname;
}
/* NULL result means no error */
--- 1485,1491 ----
* ExecQual to return TRUE for NULL.
*/
if (!ExecQual(qual, econtext, true))
! return &check[i];
}
/* NULL result means no error */
***************
*** 1513,1531 ****
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)));
}
}
--- 1513,1552 ----
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(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, 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-04-27 23:17:22.000000000 +0200
--- ./src/backend/executor/execUtils.c 2011-06-08 22:01:03.199845705 +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(pg_get_indrelation(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(pg_get_indrelation(index)),
! errcolnames(pg_get_indexdef_columns(RelationGetRelid(index), true))));
}
index_endscan(index_scan);
*** ./src/backend/utils/adt/ri_triggers.c.orig 2011-04-27 23:17:22.000000000 +0200
--- ./src/backend/utils/adt/ri_triggers.c 2011-06-08 19:02:20.963328977 +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-08 14:26:32.407139249 +0200
--- ./src/backend/utils/cache/relcache.c 2011-06-08 14:33:53.234238723 +0200
***************
*** 3264,3269 ****
--- 3264,3304 ----
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++;
}
*** ./src/backend/utils/error/elog.c.orig 2011-04-27 23:17:22.000000000 +0200
--- ./src/backend/utils/error/elog.c 2011-06-08 18:17:48.227271528 +0200
***************
*** 75,80 ****
--- 75,81 ----
#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"
***************
*** 972,977 ****
--- 973,1055 ----
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 ****
--- 1355,1368 ----
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 ****
--- 1388,1401 ----
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 ****
--- 1468,1481 ----
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);
***************
*** 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, ',');
+
+ /* table name */
+ appendCSVLiteral(&buf, edata->table_name);
+ appendStringInfoChar(&buf, ',');
+
+ /* column names */
+ appendCSVLiteral(&buf, edata->column_names);
+
appendStringInfoChar(&buf, '\n');
/* If in the syslogger process, try to write messages direct to file */
***************
*** 2314,2319 ****
--- 2431,2465 ----
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 ****
--- 2698,2727 ----
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/nbtree.h.orig 2011-06-08 21:28:27.000000000 +0200
--- ./src/include/access/nbtree.h 2011-06-08 21:37:58.987633782 +0200
***************
*** 571,576 ****
--- 571,577 ----
/*
* prototypes for functions in nbtinsert.c
*/
+ extern Relation pg_get_indrelation(Relation idxrel);
extern bool _bt_doinsert(Relation rel, IndexTuple itup,
IndexUniqueCheck checkUnique, Relation heapRel);
extern Buffer _bt_getstackbuf(Relation rel, BTStack stack, int access);
*** ./src/include/access/tupdesc.h.orig 2011-04-27 23:17:22.000000000 +0200
--- ./src/include/access/tupdesc.h 2011-06-08 14:05:49.352862942 +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-04-27 23:17:22.000000000 +0200
--- ./src/include/postgres_ext.h 2011-06-08 18:17:38.011315545 +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-04-27 23:17:22.000000000 +0200
--- ./src/include/utils/elog.h 2011-06-08 15:25:56.468098081 +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/interfaces/libpq/fe-protocol3.c.orig 2011-04-27 23:17:22.000000000 +0200
--- ./src/interfaces/libpq/fe-protocol3.c 2011-06-08 18:22:26.398132118 +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 ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers