From a60b0dc84907c323f553815dcd14e36d90ad326d Mon Sep 17 00:00:00 2001
From: Craig Ringer <craig.ringer@2ndquadrant.com>
Date: Thu, 3 Sep 2020 13:53:29 +0800
Subject: [PATCH 6/9] Add a more succinct API for error context stack callbacks

Error context stack callbacks may now be set up for a function
with:

    void
    my_function(void)
    {
        PG_ERRCONTEXT_VARS(errcb);
        struct MyFunctionCtxArgs ctxargs;

        PG_ERRCONTEXT_PUSH(errcb, the_callback_fn(), ctxargs);

        PG_ERRCONTEXT_POP(errcb);
    }

The macros push and pop the stack, maintain the previous error context stack
pointer, etc.
---
 src/include/utils/elog.h | 26 +++++++++++++++++---------
 1 file changed, 17 insertions(+), 9 deletions(-)

diff --git a/src/include/utils/elog.h b/src/include/utils/elog.h
index 33fd1ca4a9..db713907e2 100644
--- a/src/include/utils/elog.h
+++ b/src/include/utils/elog.h
@@ -256,23 +256,19 @@ extern char *format_elog_string(const char *fmt,...) pg_attribute_printf(1, 2);
  *     void
  *     my_func(void)
  *     {
- *         ErrorContextCallback errctx pgl_errcontext_check();
+ *         PG_ERRCONTEXT_VARS(errctx);
  *         struct MyFuncErrctxArg ctxarg;
  *
- *         errctx.callback = my_func_errctx_callback;
- *         errctx.arg = &ctxarg;
- *         errctx.previous = error_context_stack;
- *         error_context_stack = &errctx;
+ *         PG_ERRCONTEXT_PUSH(errctx, my_func_errctx_callback, &ctxarg);
  *
  *         // do your normal work here but (important) do NOT return without
  *         // popping the error context stack:
  *
- *         if (error_context_stack == &errctx)
- *             error_context_stack = error_context_stack->previous;
+ *         PG_ERRCONTEXT_POP(errctx);
  *     }
  *
- * It's a bit verbose, but extremely valuable for adding extra diagnostic
- * information to errors at runtime.
+ * The error context argument is optional. Your error context callback can use
+ * a constant message, global data, etc, instead.
  *------------
  */
 
@@ -285,6 +281,18 @@ typedef struct ErrorContextCallback
 
 extern PGDLLIMPORT ErrorContextCallback *error_context_stack;
 
+#define PG_ERRCONTEXT_VARS(varname) \
+	ErrorContextCallback varname pgl_errcontext_check()
+
+#define PG_ERRCONTEXT_PUSH(varname, cbfunc, cbarg) \
+	(varname).callback = (cbfunc); \
+	(varname).arg = (cbarg); \
+	(varname).previous = error_context_stack; \
+	error_context_stack = &(varname)
+
+#define PG_ERRCONTEXT_POP(varname) \
+	if (error_context_stack == &varname) \
+		error_context_stack = error_context_stack->previous
 
 /*-----------
  * Check for error context stack escapes on cassert builds.
-- 
2.26.2

