aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/src/sgml/sources.sgml6
-rw-r--r--src/backend/nls.mk4
-rw-r--r--src/backend/utils/error/elog.c75
-rw-r--r--src/backend/utils/mb/wchar.c27
-rw-r--r--src/include/utils/elog.h3
5 files changed, 81 insertions, 34 deletions
diff --git a/doc/src/sgml/sources.sgml b/doc/src/sgml/sources.sgml
index 1c8d25e4476..2248f874d06 100644
--- a/doc/src/sgml/sources.sgml
+++ b/doc/src/sgml/sources.sgml
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/sources.sgml,v 2.20 2006/10/23 18:10:32 petere Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/sources.sgml,v 2.20.2.1 2008/10/27 19:37:36 tgl Exp $ -->
<chapter id="source">
<title>PostgreSQL Coding Conventions</title>
@@ -144,7 +144,7 @@ ereport(ERROR,
<para>
<function>errmsg_internal(const char *msg, ...)</function> is the same as
<function>errmsg</>, except that the message string will not be
- included in the internationalization message dictionary.
+ translated nor included in the internationalization message dictionary.
This should be used for <quote>can't happen</> cases that are probably
not worth expending translation effort on.
</para>
@@ -220,7 +220,7 @@ elog(level, "format string", ...);
ereport(level, (errmsg_internal("format string", ...)));
</programlisting>
Notice that the SQLSTATE error code is always defaulted, and the message
- string is not included in the internationalization message dictionary.
+ string is not subject to translation.
Therefore, <function>elog</> should be used only for internal errors and
low-level debug logging. Any message that is likely to be of interest to
ordinary users should go through <function>ereport</>. Nonetheless,
diff --git a/src/backend/nls.mk b/src/backend/nls.mk
index e7da89f005c..c936d4dad4f 100644
--- a/src/backend/nls.mk
+++ b/src/backend/nls.mk
@@ -1,9 +1,7 @@
-# $PostgreSQL: pgsql/src/backend/nls.mk,v 1.20 2005/10/04 11:14:03 petere Exp $
+# $PostgreSQL: pgsql/src/backend/nls.mk,v 1.20.4.1 2008/10/27 19:37:36 tgl Exp $
CATALOG_NAME := postgres
AVAIL_LANGUAGES := af cs de es fr hr hu it ko nb pt_BR ro ru sk sl sv tr zh_CN zh_TW
GETTEXT_FILES := + gettext-files
-# you can add "elog:2" and "errmsg_internal" to this list if you want to
-# include internal messages in the translation list.
GETTEXT_TRIGGERS:= _ errmsg errdetail errhint errcontext write_stderr yyerror
gettext-files: distprep
diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c
index 3855c60d3fd..60543f7ae09 100644
--- a/src/backend/utils/error/elog.c
+++ b/src/backend/utils/error/elog.c
@@ -42,7 +42,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/error/elog.c,v 1.178.2.5 2008/07/08 22:17:55 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/error/elog.c,v 1.178.2.6 2008/10/27 19:37:36 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -125,6 +125,21 @@ static const char *error_severity(int elevel);
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
*
@@ -260,12 +275,12 @@ errstart(int elevel, const char *filename, int lineno,
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;
@@ -599,18 +614,20 @@ errcode_for_socket_access(void)
* 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); \
@@ -657,7 +674,7 @@ errmsg(const char *fmt,...)
CHECK_STACK_DEPTH();
oldcontext = MemoryContextSwitchTo(ErrorContext);
- EVALUATE_MESSAGE(message, false);
+ EVALUATE_MESSAGE(message, false, true);
MemoryContextSwitchTo(oldcontext);
recursion_depth--;
@@ -669,9 +686,12 @@ errmsg(const char *fmt,...)
* 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,...)
@@ -683,7 +703,7 @@ errmsg_internal(const char *fmt,...)
CHECK_STACK_DEPTH();
oldcontext = MemoryContextSwitchTo(ErrorContext);
- EVALUATE_MESSAGE(message, false);
+ EVALUATE_MESSAGE(message, false, false);
MemoryContextSwitchTo(oldcontext);
recursion_depth--;
@@ -704,7 +724,7 @@ errdetail(const char *fmt,...)
CHECK_STACK_DEPTH();
oldcontext = MemoryContextSwitchTo(ErrorContext);
- EVALUATE_MESSAGE(detail, false);
+ EVALUATE_MESSAGE(detail, false, true);
MemoryContextSwitchTo(oldcontext);
recursion_depth--;
@@ -725,7 +745,7 @@ errhint(const char *fmt,...)
CHECK_STACK_DEPTH();
oldcontext = MemoryContextSwitchTo(ErrorContext);
- EVALUATE_MESSAGE(hint, false);
+ EVALUATE_MESSAGE(hint, false, true);
MemoryContextSwitchTo(oldcontext);
recursion_depth--;
@@ -750,7 +770,7 @@ errcontext(const char *fmt,...)
CHECK_STACK_DEPTH();
oldcontext = MemoryContextSwitchTo(ErrorContext);
- EVALUATE_MESSAGE(context, true);
+ EVALUATE_MESSAGE(context, true, true);
MemoryContextSwitchTo(oldcontext);
recursion_depth--;
@@ -928,12 +948,12 @@ elog_finish(int elevel, const char *fmt,...)
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--;
@@ -1082,7 +1102,9 @@ ReThrowError(ErrorData *edata)
/*
* 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")));
@@ -2019,6 +2041,10 @@ useful_strerror(int errnum)
/*
* 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)
@@ -2048,13 +2074,22 @@ 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 = "???";
diff --git a/src/backend/utils/mb/wchar.c b/src/backend/utils/mb/wchar.c
index 04706460fe7..7fb54077239 100644
--- a/src/backend/utils/mb/wchar.c
+++ b/src/backend/utils/mb/wchar.c
@@ -1,7 +1,7 @@
/*
* conversion functions between pg_wchar and multibyte streams.
* Tatsuo Ishii
- * $PostgreSQL: pgsql/src/backend/utils/mb/wchar.c,v 1.58.2.2 2007/03/26 11:35:42 ishii Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/mb/wchar.c,v 1.58.2.3 2008/10/27 19:37:36 tgl Exp $
*
* WIN1250 client encoding updated by Pavel Behal
*
@@ -1556,12 +1556,25 @@ report_untranslatable_char(int src_encoding, int dest_encoding,
for (j = 0; j < jlimit; j++)
p += sprintf(p, "%02x", (unsigned char) mbstr[j]);
- ereport(ERROR,
- (errcode(ERRCODE_UNTRANSLATABLE_CHARACTER),
- errmsg("character 0x%s of encoding \"%s\" has no equivalent in \"%s\"",
- buf,
- pg_enc2name_tbl[src_encoding].name,
- pg_enc2name_tbl[dest_encoding].name)));
+ /*
+ * 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,
+ pg_enc2name_tbl[src_encoding].name,
+ pg_enc2name_tbl[dest_encoding].name)));
}
#endif
diff --git a/src/include/utils/elog.h b/src/include/utils/elog.h
index 707bc5b2fda..e0000f6ceb5 100644
--- a/src/include/utils/elog.h
+++ b/src/include/utils/elog.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/utils/elog.h,v 1.82.2.1 2008/04/17 00:00:01 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/utils/elog.h,v 1.82.2.2 2008/10/27 19:37:36 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -289,6 +289,7 @@ extern int Log_destination;
/* Other exported functions */
extern void DebugFileOpen(void);
extern char *unpack_sql_state(int sql_state);
+extern bool in_error_recursion_trouble(void);
#ifdef HAVE_SYSLOG
extern void set_syslog_parameters(const char *ident, int facility);