aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2009-03-02 21:19:23 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2009-03-02 21:19:23 +0000
commit1f3832b5d2728e5d4333324dbbb1ecd4634ded14 (patch)
tree85863ddee8d0d3150cfb61a8d679c44e0d4e23ca
parent5156266ab65d67b92493663435051a8bf36ae47d (diff)
downloadpostgresql-1f3832b5d2728e5d4333324dbbb1ecd4634ded14.tar.gz
postgresql-1f3832b5d2728e5d4333324dbbb1ecd4634ded14.zip
When we are in error recursion trouble, arrange to suppress translation and
encoding conversion of any elog/ereport message being sent to the frontend. This generalizes a patch that I put in last October, which suppressed translation of only specific messages known to be associated with recursive can't-translate-the-message behavior. As shown in bug #4680, we need a more general answer in order to have some hope of coping with broken encoding conversion setups. This approach seems a good deal less klugy anyway. Patch in all supported branches.
-rw-r--r--src/backend/libpq/pqformat.c33
-rw-r--r--src/backend/utils/error/elog.c89
-rw-r--r--src/backend/utils/mb/wchar.c17
-rw-r--r--src/include/libpq/pqformat.h3
4 files changed, 94 insertions, 48 deletions
diff --git a/src/backend/libpq/pqformat.c b/src/backend/libpq/pqformat.c
index 8241614687c..4b6b5df5a5b 100644
--- a/src/backend/libpq/pqformat.c
+++ b/src/backend/libpq/pqformat.c
@@ -24,7 +24,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Header: /cvsroot/pgsql/src/backend/libpq/pqformat.c,v 1.34 2003/08/04 02:39:59 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/libpq/pqformat.c,v 1.34.4.1 2009/03/02 21:19:23 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -41,6 +41,7 @@
* pq_sendcountedtext - append a counted text string (with character set conversion)
* pq_sendtext - append a text string (with conversion)
* pq_sendstring - append a null-terminated text string (with conversion)
+ * pq_send_ascii_string - append a null-terminated text string (without conversion)
* pq_endmessage - send the completed message to the frontend
* Note: it is also possible to append data to the StringInfo buffer using
* the regular StringInfo routines, but this is discouraged since required
@@ -189,7 +190,6 @@ void
pq_sendstring(StringInfo buf, const char *str)
{
int slen = strlen(str);
-
char *p;
p = (char *) pg_server_to_client((unsigned char *) str, slen);
@@ -204,6 +204,35 @@ pq_sendstring(StringInfo buf, const char *str)
}
/* --------------------------------
+ * pq_send_ascii_string - append a null-terminated text string (without conversion)
+ *
+ * This function intentionally bypasses encoding conversion, instead just
+ * silently replacing any non-7-bit-ASCII characters with question marks.
+ * It is used only when we are having trouble sending an error message to
+ * the client with normal localization and encoding conversion. The caller
+ * should already have taken measures to ensure the string is just ASCII;
+ * the extra work here is just to make certain we don't send a badly encoded
+ * string to the client (which might or might not be robust about that).
+ *
+ * NB: passed text string must be null-terminated, and so is the data
+ * sent to the frontend.
+ * --------------------------------
+ */
+void
+pq_send_ascii_string(StringInfo buf, const char *str)
+{
+ while (*str)
+ {
+ char ch = *str++;
+
+ if (IS_HIGHBIT_SET(ch))
+ ch = '?';
+ appendStringInfoCharMacro(buf, ch);
+ }
+ appendStringInfoChar(buf, '\0');
+}
+
+/* --------------------------------
* pq_sendint - append a binary integer to a StringInfo buffer
* --------------------------------
*/
diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c
index 5b1e3586bc0..e3a76733380 100644
--- a/src/backend/utils/error/elog.c
+++ b/src/backend/utils/error/elog.c
@@ -37,7 +37,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/error/elog.c,v 1.125.2.5 2008/10/27 19:37:56 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/error/elog.c,v 1.125.2.6 2009/03/02 21:19:23 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -64,6 +64,9 @@
#include "utils/guc.h"
+#undef _
+#define _(x) err_gettext(x)
+
/* Global variables */
ErrorContextCallback *error_context_stack = NULL;
@@ -164,6 +167,25 @@ in_error_recursion_trouble(void)
}
/*
+ * One of those fallback steps is to stop trying to localize the error
+ * message, since there's a significant probability that that's exactly
+ * what's causing the recursion.
+ */
+static inline const char *
+err_gettext(const char *str)
+{
+#ifdef ENABLE_NLS
+ if (in_error_recursion_trouble())
+ return str;
+ else
+ return gettext(str);
+#else
+ return str;
+#endif
+}
+
+
+/*
* errstart --- begin an error-reporting cycle
*
* Create a stack entry and store the given parameters in it. Subsequently,
@@ -644,7 +666,7 @@ errcode_for_socket_access(void)
char *fmtbuf; \
StringInfoData buf; \
/* Internationalize the error format string */ \
- if (translateit) \
+ if (translateit && !in_error_recursion_trouble()) \
fmt = gettext(fmt); \
/* Expand %m in format string */ \
fmtbuf = expand_fmt_string(fmt, edata); \
@@ -1197,6 +1219,26 @@ send_message_to_server_log(ErrorData *edata)
/*
+ * Append a text string to the error report being built for the client.
+ *
+ * This is ordinarily identical to pq_sendstring(), but if we are in
+ * error recursion trouble we skip encoding conversion, because of the
+ * possibility that the problem is a failure in the encoding conversion
+ * subsystem itself. Code elsewhere should ensure that the passed-in
+ * strings will be plain 7-bit ASCII, and thus not in need of conversion,
+ * in such cases. (In particular, we disable localization of error messages
+ * to help ensure that's true.)
+ */
+static void
+err_sendstring(StringInfo buf, const char *str)
+{
+ if (in_error_recursion_trouble())
+ pq_send_ascii_string(buf, str);
+ else
+ pq_sendstring(buf, str);
+}
+
+/*
* Write error report to client
*/
static void
@@ -1215,7 +1257,7 @@ send_message_to_frontend(ErrorData *edata)
int i;
pq_sendbyte(&msgbuf, PG_DIAG_SEVERITY);
- pq_sendstring(&msgbuf, error_severity(edata->elevel));
+ err_sendstring(&msgbuf, error_severity(edata->elevel));
/* unpack MAKE_SQLSTATE code */
ssval = edata->sqlerrcode;
@@ -1227,57 +1269,57 @@ send_message_to_frontend(ErrorData *edata)
tbuf[i] = '\0';
pq_sendbyte(&msgbuf, PG_DIAG_SQLSTATE);
- pq_sendstring(&msgbuf, tbuf);
+ err_sendstring(&msgbuf, tbuf);
/* M field is required per protocol, so always send something */
pq_sendbyte(&msgbuf, PG_DIAG_MESSAGE_PRIMARY);
if (edata->message)
- pq_sendstring(&msgbuf, edata->message);
+ err_sendstring(&msgbuf, edata->message);
else
- pq_sendstring(&msgbuf, gettext("missing error text"));
+ err_sendstring(&msgbuf, gettext("missing error text"));
if (edata->detail)
{
pq_sendbyte(&msgbuf, PG_DIAG_MESSAGE_DETAIL);
- pq_sendstring(&msgbuf, edata->detail);
+ err_sendstring(&msgbuf, edata->detail);
}
if (edata->hint)
{
pq_sendbyte(&msgbuf, PG_DIAG_MESSAGE_HINT);
- pq_sendstring(&msgbuf, edata->hint);
+ err_sendstring(&msgbuf, edata->hint);
}
if (edata->context)
{
pq_sendbyte(&msgbuf, PG_DIAG_CONTEXT);
- pq_sendstring(&msgbuf, edata->context);
+ err_sendstring(&msgbuf, edata->context);
}
if (edata->cursorpos > 0)
{
snprintf(tbuf, sizeof(tbuf), "%d", edata->cursorpos);
pq_sendbyte(&msgbuf, PG_DIAG_STATEMENT_POSITION);
- pq_sendstring(&msgbuf, tbuf);
+ err_sendstring(&msgbuf, tbuf);
}
if (edata->filename)
{
pq_sendbyte(&msgbuf, PG_DIAG_SOURCE_FILE);
- pq_sendstring(&msgbuf, edata->filename);
+ err_sendstring(&msgbuf, edata->filename);
}
if (edata->lineno > 0)
{
snprintf(tbuf, sizeof(tbuf), "%d", edata->lineno);
pq_sendbyte(&msgbuf, PG_DIAG_SOURCE_LINE);
- pq_sendstring(&msgbuf, tbuf);
+ err_sendstring(&msgbuf, tbuf);
}
if (edata->funcname)
{
pq_sendbyte(&msgbuf, PG_DIAG_SOURCE_FUNCTION);
- pq_sendstring(&msgbuf, edata->funcname);
+ err_sendstring(&msgbuf, edata->funcname);
}
pq_sendbyte(&msgbuf, '\0'); /* terminator */
@@ -1305,7 +1347,7 @@ send_message_to_frontend(ErrorData *edata)
appendStringInfoChar(&buf, '\n');
- pq_sendstring(&msgbuf, buf.data);
+ err_sendstring(&msgbuf, buf.data);
pfree(buf.data);
}
@@ -1415,10 +1457,6 @@ 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)
@@ -1448,22 +1486,13 @@ error_severity(int elevel)
prefix = gettext("WARNING");
break;
case ERROR:
- if (in_error_recursion_trouble())
- prefix = "ERROR";
- else
- prefix = gettext("ERROR");
+ prefix = gettext("ERROR");
break;
case FATAL:
- if (in_error_recursion_trouble())
- prefix = "FATAL";
- else
- prefix = gettext("FATAL");
+ prefix = gettext("FATAL");
break;
case PANIC:
- if (in_error_recursion_trouble())
- prefix = "PANIC";
- else
- prefix = gettext("PANIC");
+ prefix = gettext("PANIC");
break;
default:
prefix = "???";
diff --git a/src/backend/utils/mb/wchar.c b/src/backend/utils/mb/wchar.c
index 4479df474e9..b178275b1ba 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
- * $Id: wchar.c,v 1.34.2.6 2009/01/29 19:25:14 tgl Exp $
+ * $Id: wchar.c,v 1.34.2.7 2009/03/02 21:19:23 tgl Exp $
*
* WIN1250 client encoding updated by Pavel Behal
*
@@ -1193,20 +1193,7 @@ report_untranslatable_char(int src_encoding, int dest_encoding,
for (j = 0; j < jlimit; j++)
p += sprintf(p, "%02x", (unsigned char) mbstr[j]);
- /*
- * 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,
+ ereport(ERROR,
(errcode(ERRCODE_UNTRANSLATABLE_CHARACTER),
errmsg("character 0x%s of encoding \"%s\" has no equivalent in \"%s\"",
buf,
diff --git a/src/include/libpq/pqformat.h b/src/include/libpq/pqformat.h
index d04573634f9..d035694b70b 100644
--- a/src/include/libpq/pqformat.h
+++ b/src/include/libpq/pqformat.h
@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: pqformat.h,v 1.20 2003/08/04 02:40:13 momjian Exp $
+ * $Id: pqformat.h,v 1.20.4.1 2009/03/02 21:19:23 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -22,6 +22,7 @@ extern void pq_sendcountedtext(StringInfo buf, const char *str, int slen,
bool countincludesself);
extern void pq_sendtext(StringInfo buf, const char *str, int slen);
extern void pq_sendstring(StringInfo buf, const char *str);
+extern void pq_send_ascii_string(StringInfo buf, const char *str);
extern void pq_sendint(StringInfo buf, int i, int b);
extern void pq_sendint64(StringInfo buf, int64 i);
extern void pq_sendfloat4(StringInfo buf, float4 f);