>From 702e0ac31f3d8023ad8c064d90bdf5a8441fddea Mon Sep 17 00:00:00 2001
From: Craig Ringer <craig@2ndquadrant.com>
Date: Fri, 17 Oct 2014 11:18:18 +0800
Subject: [PATCH 1/2] Add an errhint_log, akin to errdetail_log

This allows a different HINT to be sent to the server error log
and to the client, which will be useful where there's security
sensitive information that's more appropriate for a HINT than
a DETAIL message.
---
 src/backend/utils/error/elog.c | 59 ++++++++++++++++++++++++++++++++----------
 src/include/utils/elog.h       |  7 +++++
 2 files changed, 53 insertions(+), 13 deletions(-)

diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c
new file mode 100644
index 2316464..da55207
*** a/src/backend/utils/error/elog.c
--- b/src/backend/utils/error/elog.c
*************** errfinish(int dummy,...)
*** 503,508 ****
--- 503,510 ----
  		pfree(edata->detail_log);
  	if (edata->hint)
  		pfree(edata->hint);
+ 	if (edata->hint_log)
+ 		pfree(edata->hint_log);
  	if (edata->context)
  		pfree(edata->context);
  	if (edata->schema_name)
*************** errhint(const char *fmt,...)
*** 1015,1020 ****
--- 1017,1042 ----
  	return 0;					/* return value does not matter */
  }
  
+ /*
+  * errhint_log --- add a hint_log error message text to the current error
+  */
+ int
+ errhint_log(const char *fmt,...)
+ {
+ 	ErrorData  *edata = &errordata[errordata_stack_depth];
+ 	MemoryContext oldcontext;
+ 
+ 	recursion_depth++;
+ 	CHECK_STACK_DEPTH();
+ 	oldcontext = MemoryContextSwitchTo(edata->assoc_context);
+ 
+ 	EVALUATE_MESSAGE(edata->domain, hint_log, false, true);
+ 
+ 	MemoryContextSwitchTo(oldcontext);
+ 	recursion_depth--;
+ 	return 0;					/* return value does not matter */
+ }
+ 
  
  /*
   * errcontext_msg --- add a context error message text to the current error
*************** CopyErrorData(void)
*** 1498,1503 ****
--- 1520,1527 ----
  		newedata->detail_log = pstrdup(newedata->detail_log);
  	if (newedata->hint)
  		newedata->hint = pstrdup(newedata->hint);
+ 	if (newedata->hint_log)
+ 		newedata->hint_log = pstrdup(newedata->hint_log);
  	if (newedata->context)
  		newedata->context = pstrdup(newedata->context);
  	if (newedata->schema_name)
*************** FreeErrorData(ErrorData *edata)
*** 1536,1541 ****
--- 1560,1567 ----
  		pfree(edata->detail_log);
  	if (edata->hint)
  		pfree(edata->hint);
+ 	if (edata->hint_log)
+ 		pfree(edata->hint_log);
  	if (edata->context)
  		pfree(edata->context);
  	if (edata->schema_name)
*************** ThrowErrorData(ErrorData *edata)
*** 1607,1612 ****
--- 1633,1640 ----
  		newedata->detail_log = pstrdup(edata->detail_log);
  	if (edata->hint)
  		newedata->hint = pstrdup(edata->hint);
+ 	if (edata->hint_log)
+ 		newedata->hint_log = pstrdup(edata->hint_log);
  	if (edata->context)
  		newedata->context = pstrdup(edata->context);
  	if (edata->schema_name)
*************** ReThrowError(ErrorData *edata)
*** 1669,1674 ****
--- 1697,1704 ----
  		newedata->detail_log = pstrdup(newedata->detail_log);
  	if (newedata->hint)
  		newedata->hint = pstrdup(newedata->hint);
+ 	if (newedata->hint_log)
+ 		newedata->hint_log = pstrdup(newedata->hint_log);
  	if (newedata->context)
  		newedata->context = pstrdup(newedata->context);
  	if (newedata->schema_name)
*************** write_csvlog(ErrorData *edata)
*** 2710,2717 ****
  		appendCSVLiteral(&buf, edata->detail);
  	appendStringInfoChar(&buf, ',');
  
! 	/* errhint */
! 	appendCSVLiteral(&buf, edata->hint);
  	appendStringInfoChar(&buf, ',');
  
  	/* internal query */
--- 2740,2750 ----
  		appendCSVLiteral(&buf, edata->detail);
  	appendStringInfoChar(&buf, ',');
  
! 	/* errhint or errhint_log */
! 	if (edata->hint_log)
! 		appendCSVLiteral(&buf, edata->hint_log);
! 	else
! 		appendCSVLiteral(&buf, edata->hint);
  	appendStringInfoChar(&buf, ',');
  
  	/* internal query */
*************** send_message_to_server_log(ErrorData *ed
*** 2828,2852 ****
  
  	if (Log_error_verbosity >= PGERROR_DEFAULT)
  	{
! 		if (edata->detail_log)
! 		{
! 			log_line_prefix(&buf, edata);
! 			appendStringInfoString(&buf, _("DETAIL:  "));
! 			append_with_tabs(&buf, edata->detail_log);
! 			appendStringInfoChar(&buf, '\n');
! 		}
! 		else if (edata->detail)
  		{
  			log_line_prefix(&buf, edata);
  			appendStringInfoString(&buf, _("DETAIL:  "));
! 			append_with_tabs(&buf, edata->detail);
  			appendStringInfoChar(&buf, '\n');
  		}
! 		if (edata->hint)
  		{
  			log_line_prefix(&buf, edata);
  			appendStringInfoString(&buf, _("HINT:  "));
! 			append_with_tabs(&buf, edata->hint);
  			appendStringInfoChar(&buf, '\n');
  		}
  		if (edata->internalquery)
--- 2861,2883 ----
  
  	if (Log_error_verbosity >= PGERROR_DEFAULT)
  	{
! 		const char	*detail = edata->detail_log != NULL
! 			? edata->detail_log : edata->detail;
! 		const char	*hint = edata->hint_log != NULL
! 			? edata->hint_log : edata->hint;
! 
! 		if (detail)
  		{
  			log_line_prefix(&buf, edata);
  			appendStringInfoString(&buf, _("DETAIL:  "));
! 			append_with_tabs(&buf, detail);
  			appendStringInfoChar(&buf, '\n');
  		}
! 		if (hint)
  		{
  			log_line_prefix(&buf, edata);
  			appendStringInfoString(&buf, _("HINT:  "));
! 			append_with_tabs(&buf, hint);
  			appendStringInfoChar(&buf, '\n');
  		}
  		if (edata->internalquery)
*************** send_message_to_frontend(ErrorData *edat
*** 3130,3135 ****
--- 3161,3168 ----
  			err_sendstring(&msgbuf, edata->hint);
  		}
  
+ 		/* hint_log is intentionally not used here */
+ 
  		if (edata->context)
  		{
  			pq_sendbyte(&msgbuf, PG_DIAG_CONTEXT);
diff --git a/src/include/utils/elog.h b/src/include/utils/elog.h
new file mode 100644
index 87438b8..7368fe1
*** a/src/include/utils/elog.h
--- b/src/include/utils/elog.h
*************** errhint(const char *fmt,...)
*** 203,208 ****
--- 203,214 ----
     the supplied arguments. */
  __attribute__((format(PG_PRINTF_ATTRIBUTE, 1, 2)));
  
+ extern int
+ errhint_log(const char *fmt,...)
+ /* This extension allows gcc to check the format string for consistency with
+    the supplied arguments. */
+ __attribute__((format(PG_PRINTF_ATTRIBUTE, 1, 2)));
+ 
  /*
   * errcontext() is typically called in error context callback functions, not
   * within an ereport() invocation. The callback function can be in a different
*************** typedef struct ErrorData
*** 395,400 ****
--- 401,407 ----
  	char	   *detail;			/* detail error message */
  	char	   *detail_log;		/* detail error message for server log only */
  	char	   *hint;			/* hint message */
+ 	char	   *hint_log;		/* hint message for server log only */
  	char	   *context;		/* context message */
  	char	   *schema_name;	/* name of schema */
  	char	   *table_name;		/* name of table */
-- 
2.1.0

