From 66c607ef6f0b7b655819b4b19383e024c5f8788c Mon Sep 17 00:00:00 2001
From: Amit Khandekar <amitdkhan.pg@gmail.com>
Date: Sat, 23 May 2020 21:39:41 +0800
Subject: [PATCH 1/3] Modularize code in toplevel pl/pgsql block callers

Functions that call exec_stmt() for executing the toplevel block have
a repetitive code that is now moved into a common function
exec_toplevel_block(). This in preparation for further changes in
this part of code.
---
 src/pl/plpgsql/src/pl_exec.c | 86 ++++++++++++++++--------------------
 1 file changed, 38 insertions(+), 48 deletions(-)

diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index 9a87cd70f1..0a70ceddbb 100644
--- a/src/pl/plpgsql/src/pl_exec.c
+++ b/src/pl/plpgsql/src/pl_exec.c
@@ -267,6 +267,9 @@ static MemoryContext get_stmt_mcontext(PLpgSQL_execstate *estate);
 static void push_stmt_mcontext(PLpgSQL_execstate *estate);
 static void pop_stmt_mcontext(PLpgSQL_execstate *estate);
 
+static void exec_toplevel_block(PLpgSQL_execstate *estate,
+								PLpgSQL_stmt_block *block,
+								char *object_type, char *err_text);
 static int	exec_stmt_block(PLpgSQL_execstate *estate,
 							PLpgSQL_stmt_block *block);
 static int	exec_stmts(PLpgSQL_execstate *estate,
@@ -475,7 +478,6 @@ plpgsql_exec_function(PLpgSQL_function *func, FunctionCallInfo fcinfo,
 	PLpgSQL_execstate estate;
 	ErrorContextCallback plerrcontext;
 	int			i;
-	int			rc;
 
 	/*
 	 * Setup the execution state
@@ -605,23 +607,8 @@ plpgsql_exec_function(PLpgSQL_function *func, FunctionCallInfo fcinfo,
 	/*
 	 * Now call the toplevel block of statements
 	 */
-	estate.err_text = NULL;
-	estate.err_stmt = (PLpgSQL_stmt *) (func->action);
-	rc = exec_stmt(&estate, (PLpgSQL_stmt *) func->action);
-	if (rc != PLPGSQL_RC_RETURN)
-	{
-		estate.err_stmt = NULL;
-		estate.err_text = NULL;
-		ereport(ERROR,
-				(errcode(ERRCODE_S_R_E_FUNCTION_EXECUTED_NO_RETURN_STATEMENT),
-				 errmsg("control reached end of function without RETURN")));
-	}
-
-	/*
-	 * We got a return value - process it
-	 */
-	estate.err_stmt = NULL;
-	estate.err_text = gettext_noop("while casting return value to function's return type");
+	exec_toplevel_block(&estate, func->action, "function",
+		gettext_noop("while casting return value to function's return type"));
 
 	fcinfo->isnull = estate.retisnull;
 
@@ -909,7 +896,7 @@ plpgsql_exec_trigger(PLpgSQL_function *func,
 {
 	PLpgSQL_execstate estate;
 	ErrorContextCallback plerrcontext;
-	int			rc;
+	int			rc PG_USED_FOR_ASSERTS_ONLY;
 	TupleDesc	tupdesc;
 	PLpgSQL_rec *rec_new,
 			   *rec_old;
@@ -1021,20 +1008,8 @@ plpgsql_exec_trigger(PLpgSQL_function *func,
 	/*
 	 * Now call the toplevel block of statements
 	 */
-	estate.err_text = NULL;
-	estate.err_stmt = (PLpgSQL_stmt *) (func->action);
-	rc = exec_stmt(&estate, (PLpgSQL_stmt *) func->action);
-	if (rc != PLPGSQL_RC_RETURN)
-	{
-		estate.err_stmt = NULL;
-		estate.err_text = NULL;
-		ereport(ERROR,
-				(errcode(ERRCODE_S_R_E_FUNCTION_EXECUTED_NO_RETURN_STATEMENT),
-				 errmsg("control reached end of trigger procedure without RETURN")));
-	}
-
-	estate.err_stmt = NULL;
-	estate.err_text = gettext_noop("during function exit");
+	exec_toplevel_block(&estate, func->action, "trigger procedure",
+						gettext_noop("during function exit"));
 
 	if (estate.retisset)
 		ereport(ERROR,
@@ -1151,7 +1126,6 @@ plpgsql_exec_event_trigger(PLpgSQL_function *func, EventTriggerData *trigdata)
 {
 	PLpgSQL_execstate estate;
 	ErrorContextCallback plerrcontext;
-	int			rc;
 
 	/*
 	 * Setup the execution state
@@ -1182,20 +1156,8 @@ plpgsql_exec_event_trigger(PLpgSQL_function *func, EventTriggerData *trigdata)
 	/*
 	 * Now call the toplevel block of statements
 	 */
-	estate.err_text = NULL;
-	estate.err_stmt = (PLpgSQL_stmt *) (func->action);
-	rc = exec_stmt(&estate, (PLpgSQL_stmt *) func->action);
-	if (rc != PLPGSQL_RC_RETURN)
-	{
-		estate.err_stmt = NULL;
-		estate.err_text = NULL;
-		ereport(ERROR,
-				(errcode(ERRCODE_S_R_E_FUNCTION_EXECUTED_NO_RETURN_STATEMENT),
-				 errmsg("control reached end of trigger procedure without RETURN")));
-	}
-
-	estate.err_stmt = NULL;
-	estate.err_text = gettext_noop("during function exit");
+	exec_toplevel_block(&estate, func->action, "trigger procedure",
+						gettext_noop("during function exit"));
 
 	/*
 	 * Let the instrumentation plugin peek at this function
@@ -1591,6 +1553,34 @@ exception_matches_conditions(ErrorData *edata, PLpgSQL_condition *cond)
 }
 
 
+/* ----------
+ * exec_toplevel_block			Execute the toplevel block
+ * ----------
+ */
+static void
+exec_toplevel_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block,
+					char *object_type, char *err_text)
+{
+	int			rc;
+
+	estate->err_text = NULL;
+	estate->err_stmt = (PLpgSQL_stmt *)block;
+
+	rc = exec_stmt(estate, (PLpgSQL_stmt *)block);
+
+	if (rc != PLPGSQL_RC_RETURN)
+	{
+		estate->err_stmt = NULL;
+		estate->err_text = NULL;
+		ereport(ERROR,
+				(errcode(ERRCODE_S_R_E_FUNCTION_EXECUTED_NO_RETURN_STATEMENT),
+				 errmsg("control reached end of %s without RETURN", object_type)));
+	}
+
+	estate->err_stmt = NULL;
+	estate->err_text = err_text;
+}
+
 /* ----------
  * exec_stmt_block			Execute a block of statements
  * ----------
-- 
2.17.1

