I wrote: > After sleeping on it, I think the right answer is to introduce the new > error-message field (and not worry about 9.5). Will work on a patch > for that, unless I hear objections pretty soon.
So far as I can find, the attached is all we need to do to introduce a new message field. (This patch doesn't address the memory-context questions, but it does fix the localization-driven failure demonstrated upthread.) Any objections? Anyone want to bikeshed the field name? I considered PG_DIAG_SEVERITY_NONLOCALIZED and PG_DIAG_SEVERITY_ENGLISH before settling on PG_DIAG_SEVERITY_ASCII, but I can't say I'm in love with that. regards, tom lane
diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml index f22e3da..40ae0ff 100644 *** a/doc/src/sgml/libpq.sgml --- b/doc/src/sgml/libpq.sgml *************** char *PQresultErrorField(const PGresult *** 2767,2772 **** --- 2767,2788 ---- </listitem> </varlistentry> + <varlistentry id="libpq-pg-diag-severity-ascii"> + <term><symbol>PG_DIAG_SEVERITY_ASCII</></term> + <listitem> + <para> + The severity; the field contents are <literal>ERROR</>, + <literal>FATAL</>, or <literal>PANIC</> (in an error message), + or <literal>WARNING</>, <literal>NOTICE</>, <literal>DEBUG</>, + <literal>INFO</>, or <literal>LOG</> (in a notice message). + This is identical to the <symbol>PG_DIAG_SEVERITY</> field except + that the contents are never localized. This is present only in + reports generated by <productname>PostgreSQL</> versions 9.6 + and later. + </para> + </listitem> + </varlistentry> + <varlistentry id="libpq-pg-diag-sqlstate"> <term> <symbol>PG_DIAG_SQLSTATE</> diff --git a/doc/src/sgml/protocol.sgml b/doc/src/sgml/protocol.sgml index 9c96d8f..9bddb19 100644 *** a/doc/src/sgml/protocol.sgml --- b/doc/src/sgml/protocol.sgml *************** message. *** 4884,4889 **** --- 4884,4908 ---- <varlistentry> <term> + <literal>A</> + </term> + <listitem> + <para> + Severity: the field contents are + <literal>ERROR</>, <literal>FATAL</>, or + <literal>PANIC</> (in an error message), or + <literal>WARNING</>, <literal>NOTICE</>, <literal>DEBUG</>, + <literal>INFO</>, or <literal>LOG</> (in a notice message). + This is identical to the <literal>S</> field except + that the contents are never localized. This is present only in + messages generated by <productname>PostgreSQL</> versions 9.6 + and later. + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term> <literal>C</> </term> <listitem> diff --git a/src/backend/libpq/pqmq.c b/src/backend/libpq/pqmq.c index 921242f..b04a7ef 100644 *** a/src/backend/libpq/pqmq.c --- b/src/backend/libpq/pqmq.c *************** pq_parse_errornotice(StringInfo msg, Err *** 237,246 **** switch (code) { case PG_DIAG_SEVERITY: if (strcmp(value, "DEBUG") == 0) ! edata->elevel = DEBUG1; /* or some other DEBUG level */ else if (strcmp(value, "LOG") == 0) ! edata->elevel = LOG; /* can't be COMMERROR */ else if (strcmp(value, "INFO") == 0) edata->elevel = INFO; else if (strcmp(value, "NOTICE") == 0) --- 237,262 ---- switch (code) { case PG_DIAG_SEVERITY: + /* ignore, trusting we'll get a nonlocalized version */ + break; + case PG_DIAG_SEVERITY_ASCII: if (strcmp(value, "DEBUG") == 0) ! { ! /* ! * We can't reconstruct the exact DEBUG level, but ! * presumably it was >= client_min_messages, so select ! * DEBUG1 to ensure we'll pass it on to the client. ! */ ! edata->elevel = DEBUG1; ! } else if (strcmp(value, "LOG") == 0) ! { ! /* ! * It can't be LOG_SERVER_ONLY, or the worker wouldn't ! * have sent it to us; so LOG is the correct value. ! */ ! edata->elevel = LOG; ! } else if (strcmp(value, "INFO") == 0) edata->elevel = INFO; else if (strcmp(value, "NOTICE") == 0) *************** pq_parse_errornotice(StringInfo msg, Err *** 254,264 **** else if (strcmp(value, "PANIC") == 0) edata->elevel = PANIC; else ! elog(ERROR, "unknown error severity"); break; case PG_DIAG_SQLSTATE: if (strlen(value) != 5) ! elog(ERROR, "malformed sql state"); edata->sqlerrcode = MAKE_SQLSTATE(value[0], value[1], value[2], value[3], value[4]); break; --- 270,280 ---- else if (strcmp(value, "PANIC") == 0) edata->elevel = PANIC; else ! elog(ERROR, "unrecognized error severity: \"%s\"", value); break; case PG_DIAG_SQLSTATE: if (strlen(value) != 5) ! elog(ERROR, "invalid SQLSTATE: \"%s\"", value); edata->sqlerrcode = MAKE_SQLSTATE(value[0], value[1], value[2], value[3], value[4]); break; *************** pq_parse_errornotice(StringInfo msg, Err *** 308,314 **** edata->funcname = pstrdup(value); break; default: ! elog(ERROR, "unknown error field: %d", (int) code); break; } } --- 324,330 ---- edata->funcname = pstrdup(value); break; default: ! elog(ERROR, "unrecognized error field code: %d", (int) code); break; } } diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c index 78d441d..ab71b50 100644 *** a/src/backend/utils/error/elog.c --- b/src/backend/utils/error/elog.c *************** write_csvlog(ErrorData *edata) *** 2744,2750 **** appendStringInfoChar(&buf, ','); /* Error severity */ ! appendStringInfoString(&buf, error_severity(edata->elevel)); appendStringInfoChar(&buf, ','); /* SQL state code */ --- 2744,2750 ---- appendStringInfoChar(&buf, ','); /* Error severity */ ! appendStringInfoString(&buf, gettext(error_severity(edata->elevel))); appendStringInfoChar(&buf, ','); /* SQL state code */ *************** send_message_to_server_log(ErrorData *ed *** 2861,2867 **** formatted_log_time[0] = '\0'; log_line_prefix(&buf, edata); ! appendStringInfo(&buf, "%s: ", error_severity(edata->elevel)); if (Log_error_verbosity >= PGERROR_VERBOSE) appendStringInfo(&buf, "%s: ", unpack_sql_state(edata->sqlerrcode)); --- 2861,2867 ---- formatted_log_time[0] = '\0'; log_line_prefix(&buf, edata); ! appendStringInfo(&buf, "%s: ", gettext(error_severity(edata->elevel))); if (Log_error_verbosity >= PGERROR_VERBOSE) appendStringInfo(&buf, "%s: ", unpack_sql_state(edata->sqlerrcode)); *************** send_message_to_frontend(ErrorData *edat *** 3144,3155 **** if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3) { /* New style with separate fields */ char tbuf[12]; int ssval; int i; pq_sendbyte(&msgbuf, PG_DIAG_SEVERITY); ! err_sendstring(&msgbuf, error_severity(edata->elevel)); /* unpack MAKE_SQLSTATE code */ ssval = edata->sqlerrcode; --- 3144,3159 ---- if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3) { /* New style with separate fields */ + const char *sev; char tbuf[12]; int ssval; int i; + sev = error_severity(edata->elevel); pq_sendbyte(&msgbuf, PG_DIAG_SEVERITY); ! err_sendstring(&msgbuf, gettext(sev)); ! pq_sendbyte(&msgbuf, PG_DIAG_SEVERITY_ASCII); ! err_sendstring(&msgbuf, sev); /* unpack MAKE_SQLSTATE code */ ssval = edata->sqlerrcode; *************** send_message_to_frontend(ErrorData *edat *** 3268,3274 **** initStringInfo(&buf); ! appendStringInfo(&buf, "%s: ", error_severity(edata->elevel)); if (edata->show_funcname && edata->funcname) appendStringInfo(&buf, "%s: ", edata->funcname); --- 3272,3278 ---- initStringInfo(&buf); ! appendStringInfo(&buf, "%s: ", gettext(error_severity(edata->elevel))); if (edata->show_funcname && edata->funcname) appendStringInfo(&buf, "%s: ", edata->funcname); *************** get_errno_symbol(int errnum) *** 3578,3584 **** /* ! * error_severity --- get localized string representing elevel */ static const char * error_severity(int elevel) --- 3582,3591 ---- /* ! * error_severity --- get string representing elevel ! * ! * The string is not localized here, but we mark the strings for translation ! * so that callers can invoke gettext on the result. */ static const char * error_severity(int elevel) *************** error_severity(int elevel) *** 3592,3620 **** case DEBUG3: case DEBUG4: case DEBUG5: ! prefix = _("DEBUG"); break; case LOG: case LOG_SERVER_ONLY: ! prefix = _("LOG"); break; case INFO: ! prefix = _("INFO"); break; case NOTICE: ! prefix = _("NOTICE"); break; case WARNING: ! prefix = _("WARNING"); break; case ERROR: ! prefix = _("ERROR"); break; case FATAL: ! prefix = _("FATAL"); break; case PANIC: ! prefix = _("PANIC"); break; default: prefix = "???"; --- 3599,3627 ---- case DEBUG3: case DEBUG4: case DEBUG5: ! prefix = gettext_noop("DEBUG"); break; case LOG: case LOG_SERVER_ONLY: ! prefix = gettext_noop("LOG"); break; case INFO: ! prefix = gettext_noop("INFO"); break; case NOTICE: ! prefix = gettext_noop("NOTICE"); break; case WARNING: ! prefix = gettext_noop("WARNING"); break; case ERROR: ! prefix = gettext_noop("ERROR"); break; case FATAL: ! prefix = gettext_noop("FATAL"); break; case PANIC: ! prefix = gettext_noop("PANIC"); break; default: prefix = "???"; diff --git a/src/include/postgres_ext.h b/src/include/postgres_ext.h index 74c344c..e318e18 100644 *** a/src/include/postgres_ext.h --- b/src/include/postgres_ext.h *************** typedef PG_INT64_TYPE pg_int64; *** 49,54 **** --- 49,55 ---- * applications. */ #define PG_DIAG_SEVERITY 'S' + #define PG_DIAG_SEVERITY_ASCII 'A' #define PG_DIAG_SQLSTATE 'C' #define PG_DIAG_MESSAGE_PRIMARY 'M' #define PG_DIAG_MESSAGE_DETAIL 'D' diff --git a/src/interfaces/libpq/fe-exec.c b/src/interfaces/libpq/fe-exec.c index d1b91c8..58c8cab 100644 *** a/src/interfaces/libpq/fe-exec.c --- b/src/interfaces/libpq/fe-exec.c *************** pqInternalNotice(const PGNoticeHooks *ho *** 824,829 **** --- 824,830 ---- */ pqSaveMessageField(res, PG_DIAG_MESSAGE_PRIMARY, msgBuf); pqSaveMessageField(res, PG_DIAG_SEVERITY, libpq_gettext("NOTICE")); + pqSaveMessageField(res, PG_DIAG_SEVERITY_ASCII, "NOTICE"); /* XXX should provide a SQLSTATE too? */ /*
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers