aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/error/elog.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/utils/error/elog.c')
-rw-r--r--src/backend/utils/error/elog.c56
1 files changed, 56 insertions, 0 deletions
diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c
index e7bc046d870..9e58735aeec 100644
--- a/src/backend/utils/error/elog.c
+++ b/src/backend/utils/error/elog.c
@@ -1156,6 +1156,62 @@ elog_finish(int elevel, const char *fmt,...)
errfinish(0);
}
+
+/*
+ * Functions to allow construction of error message strings separately from
+ * the ereport() call itself.
+ *
+ * The expected calling convention is
+ *
+ * pre_format_elog_string(errno, domain), var = format_elog_string(format,...)
+ *
+ * which can be hidden behind a macro such as GUC_check_errdetail(). We
+ * assume that any functions called in the arguments of format_elog_string()
+ * cannot result in re-entrant use of these functions --- otherwise the wrong
+ * text domain might be used, or the wrong errno substituted for %m. This is
+ * okay for the current usage with GUC check hooks, but might need further
+ * effort someday.
+ *
+ * The result of format_elog_string() is stored in ErrorContext, and will
+ * therefore survive until FlushErrorState() is called.
+ */
+static int save_format_errnumber;
+static const char *save_format_domain;
+
+void
+pre_format_elog_string(int errnumber, const char *domain)
+{
+ /* Save errno before evaluation of argument functions can change it */
+ save_format_errnumber = errnumber;
+ /* Save caller's text domain */
+ save_format_domain = domain;
+}
+
+char *
+format_elog_string(const char *fmt, ...)
+{
+ ErrorData errdata;
+ ErrorData *edata;
+ MemoryContext oldcontext;
+
+ /* Initialize a mostly-dummy error frame */
+ edata = &errdata;
+ MemSet(edata, 0, sizeof(ErrorData));
+ /* the default text domain is the backend's */
+ edata->domain = save_format_domain ? save_format_domain : PG_TEXTDOMAIN("postgres");
+ /* set the errno to be used to interpret %m */
+ edata->saved_errno = save_format_errnumber;
+
+ oldcontext = MemoryContextSwitchTo(ErrorContext);
+
+ EVALUATE_MESSAGE(message, false, true);
+
+ MemoryContextSwitchTo(oldcontext);
+
+ return edata->message;
+}
+
+
/*
* Actual output of the top-of-stack error message
*