<function>errmsg</>.
</para>
</listitem>
+ <listitem>
+ <para>
+ <function>errdetail_log(const char *msg, ...)</function> is the same as
+ <function>errdetail</> except that this string goes only to the server
+ log, never to the client. If both <function>errdetail</> and
+ <function>errdetail_log</> are used then one string goes to the client
+ and the other to the log. This is useful for error details that are
+ too security-sensitive or too bulky to include in the report
+ sent to the client.
+ </para>
+ </listitem>
<listitem>
<para>
<function>errhint(const char *msg, ...)</function> supplies an optional
pfree(edata->message);
if (edata->detail)
pfree(edata->detail);
+ if (edata->detail_log)
+ pfree(edata->detail_log);
if (edata->hint)
pfree(edata->hint);
if (edata->context)
}
+/*
+ * errdetail_log --- add a detail_log error message text to the current error
+ */
+int
+errdetail_log(const char *fmt,...)
+{
+ ErrorData *edata = &errordata[errordata_stack_depth];
+ MemoryContext oldcontext;
+
+ recursion_depth++;
+ CHECK_STACK_DEPTH();
+ oldcontext = MemoryContextSwitchTo(ErrorContext);
+
+ EVALUATE_MESSAGE(detail_log, false);
+
+ MemoryContextSwitchTo(oldcontext);
+ recursion_depth--;
+ return 0; /* return value does not matter */
+}
+
+
/*
* errhint --- add a hint error message text to the current error
*/
newedata->message = pstrdup(newedata->message);
if (newedata->detail)
newedata->detail = pstrdup(newedata->detail);
+ if (newedata->detail_log)
+ newedata->detail_log = pstrdup(newedata->detail_log);
if (newedata->hint)
newedata->hint = pstrdup(newedata->hint);
if (newedata->context)
pfree(edata->message);
if (edata->detail)
pfree(edata->detail);
+ if (edata->detail_log)
+ pfree(edata->detail_log);
if (edata->hint)
pfree(edata->hint);
if (edata->context)
newedata->message = pstrdup(newedata->message);
if (newedata->detail)
newedata->detail = pstrdup(newedata->detail);
+ if (newedata->detail_log)
+ newedata->detail_log = pstrdup(newedata->detail_log);
if (newedata->hint)
newedata->hint = pstrdup(newedata->hint);
if (newedata->context)
appendCSVLiteral(&buf, edata->message);
appendStringInfoCharMacro(&buf, ',');
- /* errdetail */
- appendCSVLiteral(&buf, edata->detail);
+ /* errdetail or errdetail_log */
+ if (edata->detail_log)
+ appendCSVLiteral(&buf, edata->detail_log);
+ else
+ appendCSVLiteral(&buf, edata->detail);
appendStringInfoCharMacro(&buf, ',');
/* errhint */
if (Log_error_verbosity >= PGERROR_DEFAULT)
{
- if (edata->detail)
+ if (edata->detail_log)
+ {
+ log_line_prefix(&buf);
+ appendStringInfoString(&buf, _("DETAIL: "));
+ append_with_tabs(&buf, edata->detail_log);
+ appendStringInfoChar(&buf, '\n');
+ }
+ else if (edata->detail)
{
log_line_prefix(&buf);
appendStringInfoString(&buf, _("DETAIL: "));
pq_sendstring(&msgbuf, edata->detail);
}
+ /* detail_log is intentionally not used here */
+
if (edata->hint)
{
pq_sendbyte(&msgbuf, PG_DIAG_MESSAGE_HINT);
the supplied arguments. */
__attribute__((format(printf, 1, 2)));
+extern int
+errdetail_log(const char *fmt,...)
+/* This extension allows gcc to check the format string for consistency with
+ the supplied arguments. */
+__attribute__((format(printf, 1, 2)));
+
extern int
errhint(const char *fmt,...)
/* This extension allows gcc to check the format string for consistency with
int sqlerrcode; /* encoded ERRSTATE */
char *message; /* primary error message */
char *detail; /* detail error message */
+ char *detail_log; /* detail error message for server log only */
char *hint; /* hint message */
char *context; /* context message */
int cursorpos; /* cursor index into query string */