mirror of
https://github.com/postgres/postgres.git
synced 2025-04-27 22:56:53 +03:00
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.
This commit is contained in:
parent
32032d42b5
commit
fd9e2accef
@ -24,7 +24,7 @@
|
|||||||
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/backend/libpq/pqformat.c,v 1.48 2009/01/01 17:23:42 momjian Exp $
|
* $PostgreSQL: pgsql/src/backend/libpq/pqformat.c,v 1.49 2009/03/02 21:18:43 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -41,6 +41,7 @@
|
|||||||
* pq_sendcountedtext - append a counted text string (with character set conversion)
|
* pq_sendcountedtext - append a counted text string (with character set conversion)
|
||||||
* pq_sendtext - append a text string (with conversion)
|
* pq_sendtext - append a text string (with conversion)
|
||||||
* pq_sendstring - append a null-terminated 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
|
* pq_endmessage - send the completed message to the frontend
|
||||||
* Note: it is also possible to append data to the StringInfo buffer using
|
* Note: it is also possible to append data to the StringInfo buffer using
|
||||||
* the regular StringInfo routines, but this is discouraged since required
|
* the regular StringInfo routines, but this is discouraged since required
|
||||||
@ -184,7 +185,6 @@ void
|
|||||||
pq_sendstring(StringInfo buf, const char *str)
|
pq_sendstring(StringInfo buf, const char *str)
|
||||||
{
|
{
|
||||||
int slen = strlen(str);
|
int slen = strlen(str);
|
||||||
|
|
||||||
char *p;
|
char *p;
|
||||||
|
|
||||||
p = pg_server_to_client(str, slen);
|
p = pg_server_to_client(str, slen);
|
||||||
@ -198,6 +198,35 @@ pq_sendstring(StringInfo buf, const char *str)
|
|||||||
appendBinaryStringInfo(buf, str, slen + 1);
|
appendBinaryStringInfo(buf, str, slen + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* --------------------------------
|
||||||
|
* 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
|
* pq_sendint - append a binary integer to a StringInfo buffer
|
||||||
* --------------------------------
|
* --------------------------------
|
||||||
|
@ -42,7 +42,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/utils/error/elog.c,v 1.212 2009/01/19 15:34:23 mha Exp $
|
* $PostgreSQL: pgsql/src/backend/utils/error/elog.c,v 1.213 2009/03/02 21:18:43 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -72,6 +72,9 @@
|
|||||||
#include "utils/ps_status.h"
|
#include "utils/ps_status.h"
|
||||||
|
|
||||||
|
|
||||||
|
#undef _
|
||||||
|
#define _(x) err_gettext(x)
|
||||||
|
|
||||||
/* Global variables */
|
/* Global variables */
|
||||||
ErrorContextCallback *error_context_stack = NULL;
|
ErrorContextCallback *error_context_stack = NULL;
|
||||||
|
|
||||||
@ -164,6 +167,25 @@ in_error_recursion_trouble(void)
|
|||||||
return (recursion_depth > 2);
|
return (recursion_depth > 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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
|
* errstart --- begin an error-reporting cycle
|
||||||
*
|
*
|
||||||
@ -631,7 +653,7 @@ errcode_for_socket_access(void)
|
|||||||
char *fmtbuf; \
|
char *fmtbuf; \
|
||||||
StringInfoData buf; \
|
StringInfoData buf; \
|
||||||
/* Internationalize the error format string */ \
|
/* Internationalize the error format string */ \
|
||||||
if (translateit) \
|
if (translateit && !in_error_recursion_trouble()) \
|
||||||
fmt = dgettext(edata->domain, fmt); \
|
fmt = dgettext(edata->domain, fmt); \
|
||||||
/* Expand %m in format string */ \
|
/* Expand %m in format string */ \
|
||||||
fmtbuf = expand_fmt_string(fmt, edata); \
|
fmtbuf = expand_fmt_string(fmt, edata); \
|
||||||
@ -2137,7 +2159,7 @@ send_message_to_server_log(ErrorData *edata)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
char *msg = _("Not safe to send CSV data\n");
|
const char *msg = _("Not safe to send CSV data\n");
|
||||||
|
|
||||||
write(fileno(stderr), msg, strlen(msg));
|
write(fileno(stderr), msg, strlen(msg));
|
||||||
if (!(Log_destination & LOG_DESTINATION_STDERR) &&
|
if (!(Log_destination & LOG_DESTINATION_STDERR) &&
|
||||||
@ -2189,6 +2211,26 @@ write_pipe_chunks(char *data, int len, int dest)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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
|
* Write error report to client
|
||||||
*/
|
*/
|
||||||
@ -2208,7 +2250,7 @@ send_message_to_frontend(ErrorData *edata)
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
pq_sendbyte(&msgbuf, PG_DIAG_SEVERITY);
|
pq_sendbyte(&msgbuf, PG_DIAG_SEVERITY);
|
||||||
pq_sendstring(&msgbuf, error_severity(edata->elevel));
|
err_sendstring(&msgbuf, error_severity(edata->elevel));
|
||||||
|
|
||||||
/* unpack MAKE_SQLSTATE code */
|
/* unpack MAKE_SQLSTATE code */
|
||||||
ssval = edata->sqlerrcode;
|
ssval = edata->sqlerrcode;
|
||||||
@ -2220,19 +2262,19 @@ send_message_to_frontend(ErrorData *edata)
|
|||||||
tbuf[i] = '\0';
|
tbuf[i] = '\0';
|
||||||
|
|
||||||
pq_sendbyte(&msgbuf, PG_DIAG_SQLSTATE);
|
pq_sendbyte(&msgbuf, PG_DIAG_SQLSTATE);
|
||||||
pq_sendstring(&msgbuf, tbuf);
|
err_sendstring(&msgbuf, tbuf);
|
||||||
|
|
||||||
/* M field is required per protocol, so always send something */
|
/* M field is required per protocol, so always send something */
|
||||||
pq_sendbyte(&msgbuf, PG_DIAG_MESSAGE_PRIMARY);
|
pq_sendbyte(&msgbuf, PG_DIAG_MESSAGE_PRIMARY);
|
||||||
if (edata->message)
|
if (edata->message)
|
||||||
pq_sendstring(&msgbuf, edata->message);
|
err_sendstring(&msgbuf, edata->message);
|
||||||
else
|
else
|
||||||
pq_sendstring(&msgbuf, _("missing error text"));
|
err_sendstring(&msgbuf, _("missing error text"));
|
||||||
|
|
||||||
if (edata->detail)
|
if (edata->detail)
|
||||||
{
|
{
|
||||||
pq_sendbyte(&msgbuf, PG_DIAG_MESSAGE_DETAIL);
|
pq_sendbyte(&msgbuf, PG_DIAG_MESSAGE_DETAIL);
|
||||||
pq_sendstring(&msgbuf, edata->detail);
|
err_sendstring(&msgbuf, edata->detail);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* detail_log is intentionally not used here */
|
/* detail_log is intentionally not used here */
|
||||||
@ -2240,52 +2282,52 @@ send_message_to_frontend(ErrorData *edata)
|
|||||||
if (edata->hint)
|
if (edata->hint)
|
||||||
{
|
{
|
||||||
pq_sendbyte(&msgbuf, PG_DIAG_MESSAGE_HINT);
|
pq_sendbyte(&msgbuf, PG_DIAG_MESSAGE_HINT);
|
||||||
pq_sendstring(&msgbuf, edata->hint);
|
err_sendstring(&msgbuf, edata->hint);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (edata->context)
|
if (edata->context)
|
||||||
{
|
{
|
||||||
pq_sendbyte(&msgbuf, PG_DIAG_CONTEXT);
|
pq_sendbyte(&msgbuf, PG_DIAG_CONTEXT);
|
||||||
pq_sendstring(&msgbuf, edata->context);
|
err_sendstring(&msgbuf, edata->context);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (edata->cursorpos > 0)
|
if (edata->cursorpos > 0)
|
||||||
{
|
{
|
||||||
snprintf(tbuf, sizeof(tbuf), "%d", edata->cursorpos);
|
snprintf(tbuf, sizeof(tbuf), "%d", edata->cursorpos);
|
||||||
pq_sendbyte(&msgbuf, PG_DIAG_STATEMENT_POSITION);
|
pq_sendbyte(&msgbuf, PG_DIAG_STATEMENT_POSITION);
|
||||||
pq_sendstring(&msgbuf, tbuf);
|
err_sendstring(&msgbuf, tbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (edata->internalpos > 0)
|
if (edata->internalpos > 0)
|
||||||
{
|
{
|
||||||
snprintf(tbuf, sizeof(tbuf), "%d", edata->internalpos);
|
snprintf(tbuf, sizeof(tbuf), "%d", edata->internalpos);
|
||||||
pq_sendbyte(&msgbuf, PG_DIAG_INTERNAL_POSITION);
|
pq_sendbyte(&msgbuf, PG_DIAG_INTERNAL_POSITION);
|
||||||
pq_sendstring(&msgbuf, tbuf);
|
err_sendstring(&msgbuf, tbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (edata->internalquery)
|
if (edata->internalquery)
|
||||||
{
|
{
|
||||||
pq_sendbyte(&msgbuf, PG_DIAG_INTERNAL_QUERY);
|
pq_sendbyte(&msgbuf, PG_DIAG_INTERNAL_QUERY);
|
||||||
pq_sendstring(&msgbuf, edata->internalquery);
|
err_sendstring(&msgbuf, edata->internalquery);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (edata->filename)
|
if (edata->filename)
|
||||||
{
|
{
|
||||||
pq_sendbyte(&msgbuf, PG_DIAG_SOURCE_FILE);
|
pq_sendbyte(&msgbuf, PG_DIAG_SOURCE_FILE);
|
||||||
pq_sendstring(&msgbuf, edata->filename);
|
err_sendstring(&msgbuf, edata->filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (edata->lineno > 0)
|
if (edata->lineno > 0)
|
||||||
{
|
{
|
||||||
snprintf(tbuf, sizeof(tbuf), "%d", edata->lineno);
|
snprintf(tbuf, sizeof(tbuf), "%d", edata->lineno);
|
||||||
pq_sendbyte(&msgbuf, PG_DIAG_SOURCE_LINE);
|
pq_sendbyte(&msgbuf, PG_DIAG_SOURCE_LINE);
|
||||||
pq_sendstring(&msgbuf, tbuf);
|
err_sendstring(&msgbuf, tbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (edata->funcname)
|
if (edata->funcname)
|
||||||
{
|
{
|
||||||
pq_sendbyte(&msgbuf, PG_DIAG_SOURCE_FUNCTION);
|
pq_sendbyte(&msgbuf, PG_DIAG_SOURCE_FUNCTION);
|
||||||
pq_sendstring(&msgbuf, edata->funcname);
|
err_sendstring(&msgbuf, edata->funcname);
|
||||||
}
|
}
|
||||||
|
|
||||||
pq_sendbyte(&msgbuf, '\0'); /* terminator */
|
pq_sendbyte(&msgbuf, '\0'); /* terminator */
|
||||||
@ -2316,7 +2358,7 @@ send_message_to_frontend(ErrorData *edata)
|
|||||||
|
|
||||||
appendStringInfoChar(&buf, '\n');
|
appendStringInfoChar(&buf, '\n');
|
||||||
|
|
||||||
pq_sendstring(&msgbuf, buf.data);
|
err_sendstring(&msgbuf, buf.data);
|
||||||
|
|
||||||
pfree(buf.data);
|
pfree(buf.data);
|
||||||
}
|
}
|
||||||
@ -2430,10 +2472,6 @@ useful_strerror(int errnum)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* error_severity --- get localized string representing elevel
|
* 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 *
|
static const char *
|
||||||
error_severity(int elevel)
|
error_severity(int elevel)
|
||||||
@ -2463,21 +2501,12 @@ error_severity(int elevel)
|
|||||||
prefix = _("WARNING");
|
prefix = _("WARNING");
|
||||||
break;
|
break;
|
||||||
case ERROR:
|
case ERROR:
|
||||||
if (in_error_recursion_trouble())
|
|
||||||
prefix = "ERROR";
|
|
||||||
else
|
|
||||||
prefix = _("ERROR");
|
prefix = _("ERROR");
|
||||||
break;
|
break;
|
||||||
case FATAL:
|
case FATAL:
|
||||||
if (in_error_recursion_trouble())
|
|
||||||
prefix = "FATAL";
|
|
||||||
else
|
|
||||||
prefix = _("FATAL");
|
prefix = _("FATAL");
|
||||||
break;
|
break;
|
||||||
case PANIC:
|
case PANIC:
|
||||||
if (in_error_recursion_trouble())
|
|
||||||
prefix = "PANIC";
|
|
||||||
else
|
|
||||||
prefix = _("PANIC");
|
prefix = _("PANIC");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* conversion functions between pg_wchar and multibyte streams.
|
* conversion functions between pg_wchar and multibyte streams.
|
||||||
* Tatsuo Ishii
|
* Tatsuo Ishii
|
||||||
* $PostgreSQL: pgsql/src/backend/utils/mb/wchar.c,v 1.71 2009/02/10 19:29:39 petere Exp $
|
* $PostgreSQL: pgsql/src/backend/utils/mb/wchar.c,v 1.72 2009/03/02 21:18:43 tgl Exp $
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
/* can be used in either frontend or backend */
|
/* can be used in either frontend or backend */
|
||||||
@ -1636,19 +1636,6 @@ report_untranslatable_char(int src_encoding, int dest_encoding,
|
|||||||
for (j = 0; j < jlimit; j++)
|
for (j = 0; j < jlimit; j++)
|
||||||
p += sprintf(p, "%02x", (unsigned char) mbstr[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),
|
(errcode(ERRCODE_UNTRANSLATABLE_CHARACTER),
|
||||||
errmsg("character 0x%s of encoding \"%s\" has no equivalent in \"%s\"",
|
errmsg("character 0x%s of encoding \"%s\" has no equivalent in \"%s\"",
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/libpq/pqformat.h,v 1.27 2009/01/01 17:23:59 momjian Exp $
|
* $PostgreSQL: pgsql/src/include/libpq/pqformat.h,v 1.28 2009/03/02 21:18:43 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -22,6 +22,7 @@ extern void pq_sendcountedtext(StringInfo buf, const char *str, int slen,
|
|||||||
bool countincludesself);
|
bool countincludesself);
|
||||||
extern void pq_sendtext(StringInfo buf, const char *str, int slen);
|
extern void pq_sendtext(StringInfo buf, const char *str, int slen);
|
||||||
extern void pq_sendstring(StringInfo buf, const char *str);
|
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_sendint(StringInfo buf, int i, int b);
|
||||||
extern void pq_sendint64(StringInfo buf, int64 i);
|
extern void pq_sendint64(StringInfo buf, int64 i);
|
||||||
extern void pq_sendfloat4(StringInfo buf, float4 f);
|
extern void pq_sendfloat4(StringInfo buf, float4 f);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user