Commit dbdf9679 authored by Heikki Linnakangas's avatar Heikki Linnakangas

Use correct text domain for translating errcontext() messages.

errcontext() is typically used in an error context callback function, not
within an ereport() invocation like e.g errmsg and errdetail are. That means
that the message domain that the TEXTDOMAIN magic in ereport() determines
is not the right one for the errcontext() calls. The message domain needs to
be determined by the C file containing the errcontext() call, not the file
containing the ereport() call.

Fix by turning errcontext() into a macro that passes the TEXTDOMAIN to use
for the errcontext message. "errcontext" was used in a few places as a
variable or struct field name, I had to rename those out of the way, now
that errcontext is a macro.

We've had this problem all along, but this isn't doesn't seem worth
backporting. It's a fairly minor issue, and turning errcontext from a
function to a macro requires at least a recompile of any external code that
calls errcontext().
parent c9d44a75
...@@ -5698,7 +5698,7 @@ StartupXLOG(void) ...@@ -5698,7 +5698,7 @@ StartupXLOG(void)
bool recoveryContinue = true; bool recoveryContinue = true;
bool recoveryApply = true; bool recoveryApply = true;
bool recoveryPause = false; bool recoveryPause = false;
ErrorContextCallback errcontext; ErrorContextCallback errcallback;
TimestampTz xtime; TimestampTz xtime;
InRedo = true; InRedo = true;
...@@ -5760,10 +5760,10 @@ StartupXLOG(void) ...@@ -5760,10 +5760,10 @@ StartupXLOG(void)
} }
/* Setup error traceback support for ereport() */ /* Setup error traceback support for ereport() */
errcontext.callback = rm_redo_error_callback; errcallback.callback = rm_redo_error_callback;
errcontext.arg = (void *) record; errcallback.arg = (void *) record;
errcontext.previous = error_context_stack; errcallback.previous = error_context_stack;
error_context_stack = &errcontext; error_context_stack = &errcallback;
/* /*
* ShmemVariableCache->nextXid must be beyond record's xid. * ShmemVariableCache->nextXid must be beyond record's xid.
...@@ -5808,7 +5808,7 @@ StartupXLOG(void) ...@@ -5808,7 +5808,7 @@ StartupXLOG(void)
RmgrTable[record->xl_rmid].rm_redo(EndRecPtr, record); RmgrTable[record->xl_rmid].rm_redo(EndRecPtr, record);
/* Pop the error context stack */ /* Pop the error context stack */
error_context_stack = errcontext.previous; error_context_stack = errcallback.previous;
if (!XLogRecPtrIsInvalid(ControlFile->backupStartPoint) && if (!XLogRecPtrIsInvalid(ControlFile->backupStartPoint) &&
XLByteLE(ControlFile->backupEndPoint, EndRecPtr)) XLByteLE(ControlFile->backupEndPoint, EndRecPtr))
......
...@@ -1901,7 +1901,7 @@ CopyFrom(CopyState cstate) ...@@ -1901,7 +1901,7 @@ CopyFrom(CopyState cstate)
TupleTableSlot *myslot; TupleTableSlot *myslot;
MemoryContext oldcontext = CurrentMemoryContext; MemoryContext oldcontext = CurrentMemoryContext;
ErrorContextCallback errcontext; ErrorContextCallback errcallback;
CommandId mycid = GetCurrentCommandId(true); CommandId mycid = GetCurrentCommandId(true);
int hi_options = 0; /* start with default heap_insert options */ int hi_options = 0; /* start with default heap_insert options */
BulkInsertState bistate; BulkInsertState bistate;
...@@ -2046,10 +2046,10 @@ CopyFrom(CopyState cstate) ...@@ -2046,10 +2046,10 @@ CopyFrom(CopyState cstate)
econtext = GetPerTupleExprContext(estate); econtext = GetPerTupleExprContext(estate);
/* Set up callback to identify error line number */ /* Set up callback to identify error line number */
errcontext.callback = CopyFromErrorCallback; errcallback.callback = CopyFromErrorCallback;
errcontext.arg = (void *) cstate; errcallback.arg = (void *) cstate;
errcontext.previous = error_context_stack; errcallback.previous = error_context_stack;
error_context_stack = &errcontext; error_context_stack = &errcallback;
for (;;) for (;;)
{ {
...@@ -2164,7 +2164,7 @@ CopyFrom(CopyState cstate) ...@@ -2164,7 +2164,7 @@ CopyFrom(CopyState cstate)
nBufferedTuples, bufferedTuples); nBufferedTuples, bufferedTuples);
/* Done, clean up */ /* Done, clean up */
error_context_stack = errcontext.previous; error_context_stack = errcallback.previous;
FreeBulkInsertState(bistate); FreeBulkInsertState(bistate);
......
...@@ -145,10 +145,10 @@ setup_parser_errposition_callback(ParseCallbackState *pcbstate, ...@@ -145,10 +145,10 @@ setup_parser_errposition_callback(ParseCallbackState *pcbstate,
/* Setup error traceback support for ereport() */ /* Setup error traceback support for ereport() */
pcbstate->pstate = pstate; pcbstate->pstate = pstate;
pcbstate->location = location; pcbstate->location = location;
pcbstate->errcontext.callback = pcb_error_callback; pcbstate->errcallback.callback = pcb_error_callback;
pcbstate->errcontext.arg = (void *) pcbstate; pcbstate->errcallback.arg = (void *) pcbstate;
pcbstate->errcontext.previous = error_context_stack; pcbstate->errcallback.previous = error_context_stack;
error_context_stack = &pcbstate->errcontext; error_context_stack = &pcbstate->errcallback;
} }
/* /*
...@@ -158,7 +158,7 @@ void ...@@ -158,7 +158,7 @@ void
cancel_parser_errposition_callback(ParseCallbackState *pcbstate) cancel_parser_errposition_callback(ParseCallbackState *pcbstate)
{ {
/* Pop the error context stack */ /* Pop the error context stack */
error_context_stack = pcbstate->errcontext.previous; error_context_stack = pcbstate->errcallback.previous;
} }
/* /*
......
...@@ -1888,7 +1888,7 @@ static void ...@@ -1888,7 +1888,7 @@ static void
FlushBuffer(volatile BufferDesc *buf, SMgrRelation reln) FlushBuffer(volatile BufferDesc *buf, SMgrRelation reln)
{ {
XLogRecPtr recptr; XLogRecPtr recptr;
ErrorContextCallback errcontext; ErrorContextCallback errcallback;
instr_time io_start, instr_time io_start,
io_time; io_time;
...@@ -1901,10 +1901,10 @@ FlushBuffer(volatile BufferDesc *buf, SMgrRelation reln) ...@@ -1901,10 +1901,10 @@ FlushBuffer(volatile BufferDesc *buf, SMgrRelation reln)
return; return;
/* Setup error traceback support for ereport() */ /* Setup error traceback support for ereport() */
errcontext.callback = shared_buffer_write_error_callback; errcallback.callback = shared_buffer_write_error_callback;
errcontext.arg = (void *) buf; errcallback.arg = (void *) buf;
errcontext.previous = error_context_stack; errcallback.previous = error_context_stack;
error_context_stack = &errcontext; error_context_stack = &errcallback;
/* Find smgr relation for buffer */ /* Find smgr relation for buffer */
if (reln == NULL) if (reln == NULL)
...@@ -1967,7 +1967,7 @@ FlushBuffer(volatile BufferDesc *buf, SMgrRelation reln) ...@@ -1967,7 +1967,7 @@ FlushBuffer(volatile BufferDesc *buf, SMgrRelation reln)
reln->smgr_rnode.node.relNode); reln->smgr_rnode.node.relNode);
/* Pop the error context stack */ /* Pop the error context stack */
error_context_stack = errcontext.previous; error_context_stack = errcallback.previous;
} }
/* /*
...@@ -2253,13 +2253,13 @@ FlushRelationBuffers(Relation rel) ...@@ -2253,13 +2253,13 @@ FlushRelationBuffers(Relation rel)
if (RelFileNodeEquals(bufHdr->tag.rnode, rel->rd_node) && if (RelFileNodeEquals(bufHdr->tag.rnode, rel->rd_node) &&
(bufHdr->flags & BM_VALID) && (bufHdr->flags & BM_DIRTY)) (bufHdr->flags & BM_VALID) && (bufHdr->flags & BM_DIRTY))
{ {
ErrorContextCallback errcontext; ErrorContextCallback errcallback;
/* Setup error traceback support for ereport() */ /* Setup error traceback support for ereport() */
errcontext.callback = local_buffer_write_error_callback; errcallback.callback = local_buffer_write_error_callback;
errcontext.arg = (void *) bufHdr; errcallback.arg = (void *) bufHdr;
errcontext.previous = error_context_stack; errcallback.previous = error_context_stack;
error_context_stack = &errcontext; error_context_stack = &errcallback;
smgrwrite(rel->rd_smgr, smgrwrite(rel->rd_smgr,
bufHdr->tag.forkNum, bufHdr->tag.forkNum,
...@@ -2270,7 +2270,7 @@ FlushRelationBuffers(Relation rel) ...@@ -2270,7 +2270,7 @@ FlushRelationBuffers(Relation rel)
bufHdr->flags &= ~(BM_DIRTY | BM_JUST_DIRTIED); bufHdr->flags &= ~(BM_DIRTY | BM_JUST_DIRTIED);
/* Pop the error context stack */ /* Pop the error context stack */
error_context_stack = errcontext.previous; error_context_stack = errcallback.previous;
} }
} }
......
...@@ -683,13 +683,13 @@ errcode_for_socket_access(void) ...@@ -683,13 +683,13 @@ errcode_for_socket_access(void)
* to the edata field because the buffer might be considerably larger than * to the edata field because the buffer might be considerably larger than
* really necessary. * really necessary.
*/ */
#define EVALUATE_MESSAGE(targetfield, appendval, translateit) \ #define EVALUATE_MESSAGE(domain, targetfield, appendval, translateit) \
{ \ { \
char *fmtbuf; \ char *fmtbuf; \
StringInfoData buf; \ StringInfoData buf; \
/* Internationalize the error format string */ \ /* Internationalize the error format string */ \
if (translateit && !in_error_recursion_trouble()) \ if (translateit && !in_error_recursion_trouble()) \
fmt = dgettext(edata->domain, fmt); \ fmt = dgettext((domain), fmt); \
/* Expand %m in format string */ \ /* Expand %m in format string */ \
fmtbuf = expand_fmt_string(fmt, edata); \ fmtbuf = expand_fmt_string(fmt, edata); \
initStringInfo(&buf); \ initStringInfo(&buf); \
...@@ -723,14 +723,14 @@ errcode_for_socket_access(void) ...@@ -723,14 +723,14 @@ errcode_for_socket_access(void)
* must be declared like "const char *fmt_singular, const char *fmt_plural, * must be declared like "const char *fmt_singular, const char *fmt_plural,
* unsigned long n, ...". Translation is assumed always wanted. * unsigned long n, ...". Translation is assumed always wanted.
*/ */
#define EVALUATE_MESSAGE_PLURAL(targetfield, appendval) \ #define EVALUATE_MESSAGE_PLURAL(domain, targetfield, appendval) \
{ \ { \
const char *fmt; \ const char *fmt; \
char *fmtbuf; \ char *fmtbuf; \
StringInfoData buf; \ StringInfoData buf; \
/* Internationalize the error format string */ \ /* Internationalize the error format string */ \
if (!in_error_recursion_trouble()) \ if (!in_error_recursion_trouble()) \
fmt = dngettext(edata->domain, fmt_singular, fmt_plural, n); \ fmt = dngettext((domain), fmt_singular, fmt_plural, n); \
else \ else \
fmt = (n == 1 ? fmt_singular : fmt_plural); \ fmt = (n == 1 ? fmt_singular : fmt_plural); \
/* Expand %m in format string */ \ /* Expand %m in format string */ \
...@@ -781,7 +781,7 @@ errmsg(const char *fmt,...) ...@@ -781,7 +781,7 @@ errmsg(const char *fmt,...)
CHECK_STACK_DEPTH(); CHECK_STACK_DEPTH();
oldcontext = MemoryContextSwitchTo(ErrorContext); oldcontext = MemoryContextSwitchTo(ErrorContext);
EVALUATE_MESSAGE(message, false, true); EVALUATE_MESSAGE(edata->domain, message, false, true);
MemoryContextSwitchTo(oldcontext); MemoryContextSwitchTo(oldcontext);
recursion_depth--; recursion_depth--;
...@@ -810,7 +810,7 @@ errmsg_internal(const char *fmt,...) ...@@ -810,7 +810,7 @@ errmsg_internal(const char *fmt,...)
CHECK_STACK_DEPTH(); CHECK_STACK_DEPTH();
oldcontext = MemoryContextSwitchTo(ErrorContext); oldcontext = MemoryContextSwitchTo(ErrorContext);
EVALUATE_MESSAGE(message, false, false); EVALUATE_MESSAGE(edata->domain, message, false, false);
MemoryContextSwitchTo(oldcontext); MemoryContextSwitchTo(oldcontext);
recursion_depth--; recursion_depth--;
...@@ -833,7 +833,7 @@ errmsg_plural(const char *fmt_singular, const char *fmt_plural, ...@@ -833,7 +833,7 @@ errmsg_plural(const char *fmt_singular, const char *fmt_plural,
CHECK_STACK_DEPTH(); CHECK_STACK_DEPTH();
oldcontext = MemoryContextSwitchTo(ErrorContext); oldcontext = MemoryContextSwitchTo(ErrorContext);
EVALUATE_MESSAGE_PLURAL(message, false); EVALUATE_MESSAGE_PLURAL(edata->domain, message, false);
MemoryContextSwitchTo(oldcontext); MemoryContextSwitchTo(oldcontext);
recursion_depth--; recursion_depth--;
...@@ -854,7 +854,7 @@ errdetail(const char *fmt,...) ...@@ -854,7 +854,7 @@ errdetail(const char *fmt,...)
CHECK_STACK_DEPTH(); CHECK_STACK_DEPTH();
oldcontext = MemoryContextSwitchTo(ErrorContext); oldcontext = MemoryContextSwitchTo(ErrorContext);
EVALUATE_MESSAGE(detail, false, true); EVALUATE_MESSAGE(edata->domain, detail, false, true);
MemoryContextSwitchTo(oldcontext); MemoryContextSwitchTo(oldcontext);
recursion_depth--; recursion_depth--;
...@@ -881,7 +881,7 @@ errdetail_internal(const char *fmt,...) ...@@ -881,7 +881,7 @@ errdetail_internal(const char *fmt,...)
CHECK_STACK_DEPTH(); CHECK_STACK_DEPTH();
oldcontext = MemoryContextSwitchTo(ErrorContext); oldcontext = MemoryContextSwitchTo(ErrorContext);
EVALUATE_MESSAGE(detail, false, false); EVALUATE_MESSAGE(edata->domain, detail, false, false);
MemoryContextSwitchTo(oldcontext); MemoryContextSwitchTo(oldcontext);
recursion_depth--; recursion_depth--;
...@@ -902,7 +902,7 @@ errdetail_log(const char *fmt,...) ...@@ -902,7 +902,7 @@ errdetail_log(const char *fmt,...)
CHECK_STACK_DEPTH(); CHECK_STACK_DEPTH();
oldcontext = MemoryContextSwitchTo(ErrorContext); oldcontext = MemoryContextSwitchTo(ErrorContext);
EVALUATE_MESSAGE(detail_log, false, true); EVALUATE_MESSAGE(edata->domain, detail_log, false, true);
MemoryContextSwitchTo(oldcontext); MemoryContextSwitchTo(oldcontext);
recursion_depth--; recursion_depth--;
...@@ -925,7 +925,7 @@ errdetail_plural(const char *fmt_singular, const char *fmt_plural, ...@@ -925,7 +925,7 @@ errdetail_plural(const char *fmt_singular, const char *fmt_plural,
CHECK_STACK_DEPTH(); CHECK_STACK_DEPTH();
oldcontext = MemoryContextSwitchTo(ErrorContext); oldcontext = MemoryContextSwitchTo(ErrorContext);
EVALUATE_MESSAGE_PLURAL(detail, false); EVALUATE_MESSAGE_PLURAL(edata->domain, detail, false);
MemoryContextSwitchTo(oldcontext); MemoryContextSwitchTo(oldcontext);
recursion_depth--; recursion_depth--;
...@@ -946,7 +946,7 @@ errhint(const char *fmt,...) ...@@ -946,7 +946,7 @@ errhint(const char *fmt,...)
CHECK_STACK_DEPTH(); CHECK_STACK_DEPTH();
oldcontext = MemoryContextSwitchTo(ErrorContext); oldcontext = MemoryContextSwitchTo(ErrorContext);
EVALUATE_MESSAGE(hint, false, true); EVALUATE_MESSAGE(edata->domain, hint, false, true);
MemoryContextSwitchTo(oldcontext); MemoryContextSwitchTo(oldcontext);
recursion_depth--; recursion_depth--;
...@@ -955,14 +955,14 @@ errhint(const char *fmt,...) ...@@ -955,14 +955,14 @@ errhint(const char *fmt,...)
/* /*
* errcontext --- add a context error message text to the current error * errcontext_msg --- add a context error message text to the current error
* *
* Unlike other cases, multiple calls are allowed to build up a stack of * Unlike other cases, multiple calls are allowed to build up a stack of
* context information. We assume earlier calls represent more-closely-nested * context information. We assume earlier calls represent more-closely-nested
* states. * states.
*/ */
int int
errcontext(const char *fmt,...) errcontext_msg(const char *fmt,...)
{ {
ErrorData *edata = &errordata[errordata_stack_depth]; ErrorData *edata = &errordata[errordata_stack_depth];
MemoryContext oldcontext; MemoryContext oldcontext;
...@@ -971,13 +971,35 @@ errcontext(const char *fmt,...) ...@@ -971,13 +971,35 @@ errcontext(const char *fmt,...)
CHECK_STACK_DEPTH(); CHECK_STACK_DEPTH();
oldcontext = MemoryContextSwitchTo(ErrorContext); oldcontext = MemoryContextSwitchTo(ErrorContext);
EVALUATE_MESSAGE(context, true, true); EVALUATE_MESSAGE(edata->context_domain, context, true, true);
MemoryContextSwitchTo(oldcontext); MemoryContextSwitchTo(oldcontext);
recursion_depth--; recursion_depth--;
return 0; /* return value does not matter */ return 0; /* return value does not matter */
} }
/*
* set_errcontext_domain --- set message domain to be used by errcontext()
*
* errcontext_msg() can be called from a different module than the original
* ereport(), so we cannot use the message domain passed in errstart() to
* translate it. Instead, each errcontext_msg() call should be preceded by
* a set_errcontext_domain() call to specify the domain. This is usually
* done transparently by the errcontext() macro.
*/
int
set_errcontext_domain(const char *domain)
{
ErrorData *edata = &errordata[errordata_stack_depth];
/* we don't bother incrementing recursion_depth */
CHECK_STACK_DEPTH();
edata->context_domain = domain;
return 0; /* return value does not matter */
}
/* /*
* errhidestmt --- optionally suppress STATEMENT: field of log entry * errhidestmt --- optionally suppress STATEMENT: field of log entry
...@@ -1201,7 +1223,7 @@ elog_finish(int elevel, const char *fmt,...) ...@@ -1201,7 +1223,7 @@ elog_finish(int elevel, const char *fmt,...)
recursion_depth++; recursion_depth++;
oldcontext = MemoryContextSwitchTo(ErrorContext); oldcontext = MemoryContextSwitchTo(ErrorContext);
EVALUATE_MESSAGE(message, false, false); EVALUATE_MESSAGE(edata->domain, message, false, false);
MemoryContextSwitchTo(oldcontext); MemoryContextSwitchTo(oldcontext);
recursion_depth--; recursion_depth--;
...@@ -1260,7 +1282,7 @@ format_elog_string(const char *fmt,...) ...@@ -1260,7 +1282,7 @@ format_elog_string(const char *fmt,...)
oldcontext = MemoryContextSwitchTo(ErrorContext); oldcontext = MemoryContextSwitchTo(ErrorContext);
EVALUATE_MESSAGE(message, false, true); EVALUATE_MESSAGE(edata->domain, message, false, true);
MemoryContextSwitchTo(oldcontext); MemoryContextSwitchTo(oldcontext);
......
...@@ -206,7 +206,7 @@ typedef struct ParseCallbackState ...@@ -206,7 +206,7 @@ typedef struct ParseCallbackState
{ {
ParseState *pstate; ParseState *pstate;
int location; int location;
ErrorContextCallback errcontext; ErrorContextCallback errcallback;
} ParseCallbackState; } ParseCallbackState;
......
...@@ -177,8 +177,19 @@ errhint(const char *fmt,...) ...@@ -177,8 +177,19 @@ errhint(const char *fmt,...)
the supplied arguments. */ the supplied arguments. */
__attribute__((format(PG_PRINTF_ATTRIBUTE, 1, 2))); __attribute__((format(PG_PRINTF_ATTRIBUTE, 1, 2)));
/*
* errcontext() is typically called in error context callback functions, not
* within an ereport() invocation. The callback function can be in a different
* module than the ereport() call, so the message domain passed in errstart()
* is not usually the correct domain for translating the context message.
* set_errcontext_domain() first sets the domain to be used, and
* errcontext_msg() passes the actual message.
*/
#define errcontext set_errcontext_domain(TEXTDOMAIN), errcontext_msg
extern int set_errcontext_domain(const char *domain);
extern int extern int
errcontext(const char *fmt,...) errcontext_msg(const char *fmt,...)
/* This extension allows gcc to check the format string for consistency with /* This extension allows gcc to check the format string for consistency with
the supplied arguments. */ the supplied arguments. */
__attribute__((format(PG_PRINTF_ATTRIBUTE, 1, 2))); __attribute__((format(PG_PRINTF_ATTRIBUTE, 1, 2)));
...@@ -320,6 +331,7 @@ typedef struct ErrorData ...@@ -320,6 +331,7 @@ typedef struct ErrorData
int lineno; /* __LINE__ of ereport() call */ int lineno; /* __LINE__ of ereport() call */
const char *funcname; /* __func__ of ereport() call */ const char *funcname; /* __func__ of ereport() call */
const char *domain; /* message domain */ const char *domain; /* message domain */
const char *context_domain; /* message domain for context message */
int sqlerrcode; /* encoded ERRSTATE */ int sqlerrcode; /* encoded ERRSTATE */
char *message; /* primary error message */ char *message; /* primary error message */
char *detail; /* detail error message */ char *detail; /* detail error message */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment