On 15.04.2012 00:54, Tom Lane wrote:
I really think we need to change errcontext itself to pass the correct
domain. If we are going to require a domain to be provided (and this
does require that, for correct operation), then we need to break any
code that doesn't provide it in a visible fashion.
A possibly more attractive alternative is to redefine errcontext
with a macro that allows TEXTDOMAIN to be passed in behind-the-scenes,
thus keeping source-level compatibility. We can do this with the same
type of hack we've used for many years for elog():
#define errcontext set_errcontext_domain(TEXTDOMAIN), errcontext_msg
where the actual message-passing function is now called errcontext_msg.
Ok then, here's a patch using that approach.
I had to rename a few local variables called "errcontext", because the
macro now tries to expands those and you get an error.
Note: If you want to test this at home, the original test case I posted
doesn't currently work because the text of the context messages in
PL/pgSQL have been slightly changed since I posted the original test
case, but the translations have not been updated yet. Until then, you
can manually remove the double quotes in messages like 'function \"%s\"'
in the .po file to test this.
--
Heikki Linnakangas
EnterpriseDB http://www.enterprisedb.com
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 0c301b2..a10b569 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -6504,7 +6504,7 @@ StartupXLOG(void)
bool recoveryContinue = true;
bool recoveryApply = true;
bool recoveryPause = false;
- ErrorContextCallback errcontext;
+ ErrorContextCallback errcallback;
TimestampTz xtime;
InRedo = true;
@@ -6566,10 +6566,10 @@ StartupXLOG(void)
}
/* Setup error traceback support for ereport() */
- errcontext.callback = rm_redo_error_callback;
- errcontext.arg = (void *) record;
- errcontext.previous = error_context_stack;
- error_context_stack = &errcontext;
+ errcallback.callback = rm_redo_error_callback;
+ errcallback.arg = (void *) record;
+ errcallback.previous = error_context_stack;
+ error_context_stack = &errcallback;
/*
* ShmemVariableCache->nextXid must be beyond record's xid.
@@ -6614,7 +6614,7 @@ StartupXLOG(void)
RmgrTable[record->xl_rmid].rm_redo(EndRecPtr, record);
/* Pop the error context stack */
- error_context_stack = errcontext.previous;
+ error_context_stack = errcallback.previous;
if (!XLogRecPtrIsInvalid(ControlFile->backupStartPoint) &&
XLByteLE(ControlFile->backupEndPoint, EndRecPtr))
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 95fec8d..cb7e67a 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -1854,7 +1854,7 @@ CopyFrom(CopyState cstate)
TupleTableSlot *myslot;
MemoryContext oldcontext = CurrentMemoryContext;
- ErrorContextCallback errcontext;
+ ErrorContextCallback errcallback;
CommandId mycid = GetCurrentCommandId(true);
int hi_options = 0; /* start with default heap_insert options */
BulkInsertState bistate;
@@ -1998,10 +1998,10 @@ CopyFrom(CopyState cstate)
econtext = GetPerTupleExprContext(estate);
/* Set up callback to identify error line number */
- errcontext.callback = CopyFromErrorCallback;
- errcontext.arg = (void *) cstate;
- errcontext.previous = error_context_stack;
- error_context_stack = &errcontext;
+ errcallback.callback = CopyFromErrorCallback;
+ errcallback.arg = (void *) cstate;
+ errcallback.previous = error_context_stack;
+ error_context_stack = &errcallback;
for (;;)
{
@@ -2116,7 +2116,7 @@ CopyFrom(CopyState cstate)
nBufferedTuples, bufferedTuples);
/* Done, clean up */
- error_context_stack = errcontext.previous;
+ error_context_stack = errcallback.previous;
FreeBulkInsertState(bistate);
diff --git a/src/backend/parser/parse_node.c b/src/backend/parser/parse_node.c
index 80dbdd1..33966ee 100644
--- a/src/backend/parser/parse_node.c
+++ b/src/backend/parser/parse_node.c
@@ -144,10 +144,10 @@ setup_parser_errposition_callback(ParseCallbackState *pcbstate,
/* Setup error traceback support for ereport() */
pcbstate->pstate = pstate;
pcbstate->location = location;
- pcbstate->errcontext.callback = pcb_error_callback;
- pcbstate->errcontext.arg = (void *) pcbstate;
- pcbstate->errcontext.previous = error_context_stack;
- error_context_stack = &pcbstate->errcontext;
+ pcbstate->errcallback.callback = pcb_error_callback;
+ pcbstate->errcallback.arg = (void *) pcbstate;
+ pcbstate->errcallback.previous = error_context_stack;
+ error_context_stack = &pcbstate->errcallback;
}
/*
@@ -157,7 +157,7 @@ void
cancel_parser_errposition_callback(ParseCallbackState *pcbstate)
{
/* Pop the error context stack */
- error_context_stack = pcbstate->errcontext.previous;
+ error_context_stack = pcbstate->errcallback.previous;
}
/*
diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c
index 613d754..35c8040 100644
--- a/src/backend/storage/buffer/bufmgr.c
+++ b/src/backend/storage/buffer/bufmgr.c
@@ -1888,7 +1888,7 @@ static void
FlushBuffer(volatile BufferDesc *buf, SMgrRelation reln)
{
XLogRecPtr recptr;
- ErrorContextCallback errcontext;
+ ErrorContextCallback errcallback;
instr_time io_start,
io_time;
@@ -1901,10 +1901,10 @@ FlushBuffer(volatile BufferDesc *buf, SMgrRelation reln)
return;
/* Setup error traceback support for ereport() */
- errcontext.callback = shared_buffer_write_error_callback;
- errcontext.arg = (void *) buf;
- errcontext.previous = error_context_stack;
- error_context_stack = &errcontext;
+ errcallback.callback = shared_buffer_write_error_callback;
+ errcallback.arg = (void *) buf;
+ errcallback.previous = error_context_stack;
+ error_context_stack = &errcallback;
/* Find smgr relation for buffer, and mark it as transient */
if (reln == NULL)
@@ -1970,7 +1970,7 @@ FlushBuffer(volatile BufferDesc *buf, SMgrRelation reln)
reln->smgr_rnode.node.relNode);
/* Pop the error context stack */
- error_context_stack = errcontext.previous;
+ error_context_stack = errcallback.previous;
}
/*
@@ -2189,13 +2189,13 @@ FlushRelationBuffers(Relation rel)
if (RelFileNodeEquals(bufHdr->tag.rnode, rel->rd_node) &&
(bufHdr->flags & BM_VALID) && (bufHdr->flags & BM_DIRTY))
{
- ErrorContextCallback errcontext;
+ ErrorContextCallback errcallback;
/* Setup error traceback support for ereport() */
- errcontext.callback = local_buffer_write_error_callback;
- errcontext.arg = (void *) bufHdr;
- errcontext.previous = error_context_stack;
- error_context_stack = &errcontext;
+ errcallback.callback = local_buffer_write_error_callback;
+ errcallback.arg = (void *) bufHdr;
+ errcallback.previous = error_context_stack;
+ error_context_stack = &errcallback;
smgrwrite(rel->rd_smgr,
bufHdr->tag.forkNum,
@@ -2206,7 +2206,7 @@ FlushRelationBuffers(Relation rel)
bufHdr->flags &= ~(BM_DIRTY | BM_JUST_DIRTIED);
/* Pop the error context stack */
- error_context_stack = errcontext.previous;
+ error_context_stack = errcallback.previous;
}
}
diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c
index 239ac19..1fbb10e 100644
--- a/src/backend/utils/error/elog.c
+++ b/src/backend/utils/error/elog.c
@@ -683,13 +683,13 @@ errcode_for_socket_access(void)
* to the edata field because the buffer might be considerably larger than
* really necessary.
*/
-#define EVALUATE_MESSAGE(targetfield, appendval, translateit) \
+#define EVALUATE_MESSAGE(domain, targetfield, appendval, translateit) \
{ \
char *fmtbuf; \
StringInfoData buf; \
/* Internationalize the error format string */ \
if (translateit && !in_error_recursion_trouble()) \
- fmt = dgettext(edata->domain, fmt); \
+ fmt = dgettext((domain), fmt); \
/* Expand %m in format string */ \
fmtbuf = expand_fmt_string(fmt, edata); \
initStringInfo(&buf); \
@@ -723,14 +723,14 @@ errcode_for_socket_access(void)
* must be declared like "const char *fmt_singular, const char *fmt_plural,
* unsigned long n, ...". Translation is assumed always wanted.
*/
-#define EVALUATE_MESSAGE_PLURAL(targetfield, appendval) \
+#define EVALUATE_MESSAGE_PLURAL(domain, targetfield, appendval) \
{ \
const char *fmt; \
char *fmtbuf; \
StringInfoData buf; \
/* Internationalize the error format string */ \
if (!in_error_recursion_trouble()) \
- fmt = dngettext(edata->domain, fmt_singular, fmt_plural, n); \
+ fmt = dngettext((domain), fmt_singular, fmt_plural, n); \
else \
fmt = (n == 1 ? fmt_singular : fmt_plural); \
/* Expand %m in format string */ \
@@ -781,7 +781,7 @@ errmsg(const char *fmt,...)
CHECK_STACK_DEPTH();
oldcontext = MemoryContextSwitchTo(ErrorContext);
- EVALUATE_MESSAGE(message, false, true);
+ EVALUATE_MESSAGE(edata->domain, message, false, true);
MemoryContextSwitchTo(oldcontext);
recursion_depth--;
@@ -810,7 +810,7 @@ errmsg_internal(const char *fmt,...)
CHECK_STACK_DEPTH();
oldcontext = MemoryContextSwitchTo(ErrorContext);
- EVALUATE_MESSAGE(message, false, false);
+ EVALUATE_MESSAGE(edata->domain, message, false, false);
MemoryContextSwitchTo(oldcontext);
recursion_depth--;
@@ -833,7 +833,7 @@ errmsg_plural(const char *fmt_singular, const char *fmt_plural,
CHECK_STACK_DEPTH();
oldcontext = MemoryContextSwitchTo(ErrorContext);
- EVALUATE_MESSAGE_PLURAL(message, false);
+ EVALUATE_MESSAGE_PLURAL(edata->domain, message, false);
MemoryContextSwitchTo(oldcontext);
recursion_depth--;
@@ -854,7 +854,7 @@ errdetail(const char *fmt,...)
CHECK_STACK_DEPTH();
oldcontext = MemoryContextSwitchTo(ErrorContext);
- EVALUATE_MESSAGE(detail, false, true);
+ EVALUATE_MESSAGE(edata->domain, detail, false, true);
MemoryContextSwitchTo(oldcontext);
recursion_depth--;
@@ -881,7 +881,7 @@ errdetail_internal(const char *fmt,...)
CHECK_STACK_DEPTH();
oldcontext = MemoryContextSwitchTo(ErrorContext);
- EVALUATE_MESSAGE(detail, false, false);
+ EVALUATE_MESSAGE(edata->domain, detail, false, false);
MemoryContextSwitchTo(oldcontext);
recursion_depth--;
@@ -902,7 +902,7 @@ errdetail_log(const char *fmt,...)
CHECK_STACK_DEPTH();
oldcontext = MemoryContextSwitchTo(ErrorContext);
- EVALUATE_MESSAGE(detail_log, false, true);
+ EVALUATE_MESSAGE(edata->domain, detail_log, false, true);
MemoryContextSwitchTo(oldcontext);
recursion_depth--;
@@ -925,7 +925,7 @@ errdetail_plural(const char *fmt_singular, const char *fmt_plural,
CHECK_STACK_DEPTH();
oldcontext = MemoryContextSwitchTo(ErrorContext);
- EVALUATE_MESSAGE_PLURAL(detail, false);
+ EVALUATE_MESSAGE_PLURAL(edata->domain, detail, false);
MemoryContextSwitchTo(oldcontext);
recursion_depth--;
@@ -946,7 +946,7 @@ errhint(const char *fmt,...)
CHECK_STACK_DEPTH();
oldcontext = MemoryContextSwitchTo(ErrorContext);
- EVALUATE_MESSAGE(hint, false, true);
+ EVALUATE_MESSAGE(edata->domain, hint, false, true);
MemoryContextSwitchTo(oldcontext);
recursion_depth--;
@@ -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
* context information. We assume earlier calls represent more-closely-nested
* states.
*/
int
-errcontext(const char *fmt,...)
+errcontext_msg(const char *fmt,...)
{
ErrorData *edata = &errordata[errordata_stack_depth];
MemoryContext oldcontext;
@@ -971,13 +971,35 @@ errcontext(const char *fmt,...)
CHECK_STACK_DEPTH();
oldcontext = MemoryContextSwitchTo(ErrorContext);
- EVALUATE_MESSAGE(context, true, true);
+ EVALUATE_MESSAGE(edata->context_domain, context, true, true);
MemoryContextSwitchTo(oldcontext);
recursion_depth--;
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
@@ -1201,7 +1223,7 @@ elog_finish(int elevel, const char *fmt,...)
recursion_depth++;
oldcontext = MemoryContextSwitchTo(ErrorContext);
- EVALUATE_MESSAGE(message, false, false);
+ EVALUATE_MESSAGE(edata->domain, message, false, false);
MemoryContextSwitchTo(oldcontext);
recursion_depth--;
@@ -1260,7 +1282,7 @@ format_elog_string(const char *fmt,...)
oldcontext = MemoryContextSwitchTo(ErrorContext);
- EVALUATE_MESSAGE(message, false, true);
+ EVALUATE_MESSAGE(edata->domain, message, false, true);
MemoryContextSwitchTo(oldcontext);
diff --git a/src/include/parser/parse_node.h b/src/include/parser/parse_node.h
index 670e084..1b0f0dd 100644
--- a/src/include/parser/parse_node.h
+++ b/src/include/parser/parse_node.h
@@ -126,7 +126,7 @@ typedef struct ParseCallbackState
{
ParseState *pstate;
int location;
- ErrorContextCallback errcontext;
+ ErrorContextCallback errcallback;
} ParseCallbackState;
diff --git a/src/include/utils/elog.h b/src/include/utils/elog.h
index 7b5bcfa..0c0c935 100644
--- a/src/include/utils/elog.h
+++ b/src/include/utils/elog.h
@@ -172,8 +172,20 @@ errhint(const char *fmt,...)
the supplied arguments. */
__attribute__((format(PG_PRINTF_ATTRIBUTE, 1, 2)));
+/*
+ * errcontext() is typically called in error context callback functions, not
+ * within the ereport() macro. The callback function can be in a completely
+ * different module than the ereport() call, so the message domain passed
+ * in errstart() cannot be used to translate 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
-errcontext(const char *fmt,...)
+errcontext_msg(const char *fmt,...)
/* This extension allows gcc to check the format string for consistency with
the supplied arguments. */
__attribute__((format(PG_PRINTF_ATTRIBUTE, 1, 2)));
@@ -315,6 +327,7 @@ typedef struct ErrorData
int lineno; /* __LINE__ of ereport() call */
const char *funcname; /* __func__ of ereport() call */
const char *domain; /* message domain */
+ const char *context_domain; /* message domain for context message */
int sqlerrcode; /* encoded ERRSTATE */
char *message; /* primary error message */
char *detail; /* detail error message */
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers