*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/error/elog.c,v 1.167.2.6 2008/07/08 22:18:02 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/error/elog.c,v 1.167.2.7 2008/10/27 19:37:42 tgl Exp $
*
*-------------------------------------------------------------------------
*/
static void append_with_tabs(StringInfo buf, const char *str);
static void write_pipe_chunks(int fd, char *data, int len);
+
+/*
+ * in_error_recursion_trouble --- are we at risk of infinite error recursion?
+ *
+ * This function exists to provide common control of various fallback steps
+ * that we take if we think we are facing infinite error recursion. See the
+ * callers for details.
+ */
+bool
+in_error_recursion_trouble(void)
+{
+ /* Pull the plug if recurse more than once */
+ return (recursion_depth > 2);
+}
+
/*
* errstart --- begin an error-reporting cycle
*
MemoryContextReset(ErrorContext);
/*
- * If we recurse more than once, the problem might be something broken
+ * Infinite error recursion might be due to something broken
* in a context traceback routine. Abandon them too. We also
* abandon attempting to print the error statement (which, if long,
* could itself be the source of the recursive failure).
*/
- if (recursion_depth > 2)
+ if (in_error_recursion_trouble())
{
error_context_stack = NULL;
debug_query_string = NULL;
* it's common code for errmsg(), errdetail(), etc. Must be called inside
* a routine that is declared like "const char *fmt, ..." and has an edata
* pointer set up. The message is assigned to edata->targetfield, or
- * appended to it if appendval is true.
+ * appended to it if appendval is true. The message is subject to translation
+ * if translateit is true.
*
* Note: we pstrdup the buffer rather than just transferring its storage
* to the edata field because the buffer might be considerably larger than
* really necessary.
*/
-#define EVALUATE_MESSAGE(targetfield, appendval) \
+#define EVALUATE_MESSAGE(targetfield, appendval, translateit) \
{ \
char *fmtbuf; \
StringInfoData buf; \
/* Internationalize the error format string */ \
- fmt = _(fmt); \
+ if (translateit) \
+ fmt = _(fmt); \
/* Expand %m in format string */ \
fmtbuf = expand_fmt_string(fmt, edata); \
initStringInfo(&buf); \
CHECK_STACK_DEPTH();
oldcontext = MemoryContextSwitchTo(ErrorContext);
- EVALUATE_MESSAGE(message, false);
+ EVALUATE_MESSAGE(message, false, true);
MemoryContextSwitchTo(oldcontext);
recursion_depth--;
* errmsg_internal --- add a primary error message text to the current error
*
* This is exactly like errmsg() except that strings passed to errmsg_internal
- * are customarily left out of the internationalization message dictionary.
- * This should be used for "can't happen" cases that are probably not worth
- * spending translation effort on.
+ * are not translated, and are customarily left out of the
+ * internationalization message dictionary. This should be used for "can't
+ * happen" cases that are probably not worth spending translation effort on.
+ * We also use this for certain cases where we *must* not try to translate
+ * the message because the translation would fail and result in infinite
+ * error recursion.
*/
int
errmsg_internal(const char *fmt,...)
CHECK_STACK_DEPTH();
oldcontext = MemoryContextSwitchTo(ErrorContext);
- EVALUATE_MESSAGE(message, false);
+ EVALUATE_MESSAGE(message, false, false);
MemoryContextSwitchTo(oldcontext);
recursion_depth--;
CHECK_STACK_DEPTH();
oldcontext = MemoryContextSwitchTo(ErrorContext);
- EVALUATE_MESSAGE(detail, false);
+ EVALUATE_MESSAGE(detail, false, true);
MemoryContextSwitchTo(oldcontext);
recursion_depth--;
CHECK_STACK_DEPTH();
oldcontext = MemoryContextSwitchTo(ErrorContext);
- EVALUATE_MESSAGE(hint, false);
+ EVALUATE_MESSAGE(hint, false, true);
MemoryContextSwitchTo(oldcontext);
recursion_depth--;
CHECK_STACK_DEPTH();
oldcontext = MemoryContextSwitchTo(ErrorContext);
- EVALUATE_MESSAGE(context, true);
+ EVALUATE_MESSAGE(context, true, true);
MemoryContextSwitchTo(oldcontext);
recursion_depth--;
return; /* nothing to do */
/*
- * Format error message just like errmsg().
+ * Format error message just like errmsg_internal().
*/
recursion_depth++;
oldcontext = MemoryContextSwitchTo(ErrorContext);
- EVALUATE_MESSAGE(message, false);
+ EVALUATE_MESSAGE(message, false, false);
MemoryContextSwitchTo(oldcontext);
recursion_depth--;
/*
* Wups, stack not big enough. We treat this as a PANIC condition
* because it suggests an infinite loop of errors during error
- * recovery.
+ * recovery. Note that the message is intentionally not localized,
+ * else failure to convert it to client encoding could cause further
+ * recursion.
*/
errordata_stack_depth = -1; /* make room on stack */
ereport(PANIC, (errmsg_internal("ERRORDATA_STACK_SIZE exceeded")));
/*
* error_severity --- get localized string representing elevel
+ *
+ * Note: in an error recursion situation, we stop localizing the tags
+ * for ERROR and above. This is necessary because the problem might be
+ * failure to convert one of these strings to the client encoding.
*/
static const char *
error_severity(int elevel)
prefix = _("WARNING");
break;
case ERROR:
- prefix = _("ERROR");
+ if (in_error_recursion_trouble())
+ prefix = "ERROR";
+ else
+ prefix = _("ERROR");
break;
case FATAL:
- prefix = _("FATAL");
+ if (in_error_recursion_trouble())
+ prefix = "FATAL";
+ else
+ prefix = _("FATAL");
break;
case PANIC:
- prefix = _("PANIC");
+ if (in_error_recursion_trouble())
+ prefix = "PANIC";
+ else
+ prefix = _("PANIC");
break;
default:
prefix = "???";
/*
* conversion functions between pg_wchar and multibyte streams.
* Tatsuo Ishii
- * $PostgreSQL: pgsql/src/backend/utils/mb/wchar.c,v 1.47.2.6 2007/03/26 11:43:09 ishii Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/mb/wchar.c,v 1.47.2.7 2008/10/27 19:37:42 tgl Exp $
*
* WIN1250 client encoding updated by Pavel Behal
*
for (j = 0; j < jlimit; j++)
p += sprintf(p, "%02x", (unsigned char) mbstr[j]);
- ereport(ERROR,
+ /*
+ * In an error recursion situation, don't try to translate the message.
+ * This gets us out of trouble if the problem is failure to convert
+ * this very message (after translation) to the client encoding.
+ */
+ if (in_error_recursion_trouble())
+ ereport(ERROR,
+ (errcode(ERRCODE_UNTRANSLATABLE_CHARACTER),
+ errmsg_internal("character 0x%s of encoding \"%s\" has no equivalent in \"%s\"",
+ buf,
+ pg_enc2name_tbl[src_encoding].name,
+ pg_enc2name_tbl[dest_encoding].name)));
+ else
+ ereport(ERROR,
(errcode(ERRCODE_UNTRANSLATABLE_CHARACTER),
errmsg("character 0x%s of encoding \"%s\" has no equivalent in \"%s\"",
buf,