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

Reply via email to