0001-Introduce-PG_RETURN_ERROR-and-FuncCallError-node.patch

text/x-patch

Filename: 0001-Introduce-PG_RETURN_ERROR-and-FuncCallError-node.patch
Type: text/x-patch
Part: 0
Message: Re: SQL/JSON features for v15

Patch

Format: format-patch
Series: patch 0001
Subject: Introduce PG_RETURN_ERROR and FuncCallError node
File+
src/include/nodes/execnodes.h 7 0
src/include/utils/elog.h 25 0
From 537e65e1ebcccdf4a760d3aeeeea743c88611e7c Mon Sep 17 00:00:00 2001
From: Nikita Glukhov <n.gluhov@postgrespro.ru>
Date: Wed, 31 Aug 2022 22:24:33 +0300
Subject: [PATCH 1/5] Introduce PG_RETURN_ERROR and FuncCallError node

---
 src/include/nodes/execnodes.h |  7 +++++++
 src/include/utils/elog.h      | 25 +++++++++++++++++++++++++
 2 files changed, 32 insertions(+)

diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index 01b1727fc09..b401d354656 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -2729,4 +2729,11 @@ typedef struct LimitState
 	TupleTableSlot *last_slot;	/* slot for evaluation of ties */
 } LimitState;
 
+typedef struct FuncCallError
+{
+	NodeTag		type;
+	ErrorData  *error;			/* place where function should put
+								 * error data instead of throwing it */
+} FuncCallError;
+
 #endif							/* EXECNODES_H */
diff --git a/src/include/utils/elog.h b/src/include/utils/elog.h
index 56398176901..5fd3deed61f 100644
--- a/src/include/utils/elog.h
+++ b/src/include/utils/elog.h
@@ -159,6 +159,31 @@
 #define ereport(elevel, ...)	\
 	ereport_domain(elevel, TEXTDOMAIN, __VA_ARGS__)
 
+/*
+ * PG_RETURN_ERROR() -- special macro for copying error info into the
+ * FuncCallError node, if it was as FunctionCallInfo.context,
+ * instead of throwing it with ordinary ereport().
+ *
+ * This is intended for handling of errors of categories like
+ * ERRCODE_DATA_EXCEPTION without PG_TRY/PG_CATCH and substransactions,
+ * but not for errors like ERRCODE_OUT_OF_MEMORY.
+ */
+#define PG_RETURN_ERROR(...) \
+	do { \
+		if (fcinfo->context && IsA(fcinfo->context, FuncCallError)) { \
+			pg_prevent_errno_in_scope(); \
+			\
+			errstart(ERROR, TEXTDOMAIN); \
+			(__VA_ARGS__); \
+			castNode(FuncCallError, fcinfo->context)->error = CopyErrorData(); \
+			FlushErrorState(); \
+			\
+			PG_RETURN_NULL(); \
+		} else { \
+			ereport(ERROR, (__VA_ARGS__)); \
+		} \
+	} while (0)
+
 #define TEXTDOMAIN NULL
 
 extern bool message_level_is_interesting(int elevel);
-- 
2.25.1