git.postgresql.org Git - postgresql.git/commitdiff

git projects / postgresql.git / commitdiff
? search:
summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: ecd9e9f)
Inline plpgsql's exec_stmt() into exec_stmts().
Fri, 3 Jul 2020 19:42:10 +0000 (15:42 -0400)
Fri, 3 Jul 2020 19:42:10 +0000 (15:42 -0400)
This saves one level of C function call per plpgsql statement executed,
and permits a tiny additional optimization of not saving and restoring
estate->err_stmt for each statement in a block. The net effect seems
nearly un-measurable on x86_64, but there's a clear win on aarch64,
amounting to two or three percent in a loop over a few simple plpgsql
statements.

To do this, we have to get rid of the other existing call sites for
exec_stmt(). Replace them with exec_toplevel_block(), which is just
defined to do what exec_stmts() does, but for a single
PLpgSQL_stmt_block statement. Hard-wiring the expectation of which
statement type applies here allows us to skip the dispatch switch,
making this not much uglier than the previous factorization.

Amit Khandekar, tweaked a bit by me

Discussion: https://postgr.es/m/CAJ3gD9eBNrmUD7WBBLG8ohaZ485H9y+4eihQTgr+K8Lhka3vcQ@mail.gmail.com


diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index f41d675d656342a3045da52f5049b8db68d240b3..54900e01c8f59bc2e3141c29fd8fa161c805daca 100644 (file)
--- a/src/pl/plpgsql/src/pl_exec.c
+++ b/src/pl/plpgsql/src/pl_exec.c
@@ -260,12 +260,12 @@ 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 int exec_toplevel_block(PLpgSQL_execstate *estate,
+ PLpgSQL_stmt_block *block);
static int exec_stmt_block(PLpgSQL_execstate *estate,
PLpgSQL_stmt_block *block);
static int exec_stmts(PLpgSQL_execstate *estate,
List *stmts);
-static int exec_stmt(PLpgSQL_execstate *estate,
- PLpgSQL_stmt *stmt);
static int exec_stmt_assign(PLpgSQL_execstate *estate,
PLpgSQL_stmt_assign *stmt);
static int exec_stmt_perform(PLpgSQL_execstate *estate,
@@ -599,11 +599,9 @@ 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);
+ rc = exec_toplevel_block(&estate, 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),
@@ -613,7 +611,6 @@ plpgsql_exec_function(PLpgSQL_function *func, FunctionCallInfo fcinfo,
/*
* 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");
fcinfo->isnull = estate.retisnull;
@@ -1015,18 +1012,15 @@ 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);
+ rc = exec_toplevel_block(&estate, 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");
if (estate.retisset)
@@ -1176,18 +1170,15 @@ 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);
+ rc = exec_toplevel_block(&estate, 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");
/*
@@ -1584,6 +1575,40 @@ exception_matches_conditions(ErrorData *edata, PLpgSQL_condition *cond)
}
+/* ----------
+ * exec_toplevel_block Execute the toplevel block
+ *
+ * This is intentionally equivalent to executing exec_stmts() with a
+ * list consisting of the one statement. One tiny difference is that
+ * we do not bother to save the entry value of estate->err_stmt;
+ * that's assumed to be NULL.
+ * ----------
+ */
+static int
+exec_toplevel_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
+{
+ int rc;
+
+ estate->err_stmt = (PLpgSQL_stmt *) block;
+
+ /* Let the plugin know that we are about to execute this statement */
+ if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->stmt_beg)
+ ((*plpgsql_plugin_ptr)->stmt_beg) (estate, (PLpgSQL_stmt *) block);
+
+ CHECK_FOR_INTERRUPTS();
+
+ rc = exec_stmt_block(estate, block);
+
+ /* Let the plugin know that we have finished executing this statement */
+ if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->stmt_end)
+ ((*plpgsql_plugin_ptr)->stmt_end) (estate, (PLpgSQL_stmt *) block);
+
+ estate->err_stmt = NULL;
+
+ return rc;
+}
+
+
/* ----------
* exec_stmt_block Execute a block of statements
* ----------
@@ -1917,6 +1942,7 @@ exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
static int
exec_stmts(PLpgSQL_execstate *estate, List *stmts)
{
+ PLpgSQL_stmt *save_estmt = estate->err_stmt;
ListCell *s;
if (stmts == NIL)
@@ -1933,162 +1959,150 @@ exec_stmts(PLpgSQL_execstate *estate, List *stmts)
foreach(s, stmts)
{
PLpgSQL_stmt *stmt = (PLpgSQL_stmt *) lfirst(s);
- int rc = exec_stmt(estate, stmt);
-
- if (rc != PLPGSQL_RC_OK)
- return rc;
- }
+ int rc;
- return PLPGSQL_RC_OK;
-}
+ estate->err_stmt = stmt;
+ /* Let the plugin know that we are about to execute this statement */
+ if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->stmt_beg)
+ ((*plpgsql_plugin_ptr)->stmt_beg) (estate, stmt);
-/* ----------
- * exec_stmt Distribute one statement to the statements
- * type specific execution function.
- * ----------
- */
-static int
-exec_stmt(PLpgSQL_execstate *estate, PLpgSQL_stmt *stmt)
-{
- PLpgSQL_stmt *save_estmt;
- int rc = -1;
-
- save_estmt = estate->err_stmt;
- estate->err_stmt = stmt;
+ CHECK_FOR_INTERRUPTS();
- /* Let the plugin know that we are about to execute this statement */
- if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->stmt_beg)
- ((*plpgsql_plugin_ptr)->stmt_beg) (estate, stmt);
+ switch (stmt->cmd_type)
+ {
+ case PLPGSQL_STMT_BLOCK:
+ rc = exec_stmt_block(estate, (PLpgSQL_stmt_block *) stmt);
+ break;
- CHECK_FOR_INTERRUPTS();
+ case PLPGSQL_STMT_ASSIGN:
+ rc = exec_stmt_assign(estate, (PLpgSQL_stmt_assign *) stmt);
+ break;
- switch (stmt->cmd_type)
- {
- case PLPGSQL_STMT_BLOCK:
- rc = exec_stmt_block(estate, (PLpgSQL_stmt_block *) stmt);
- break;
+ case PLPGSQL_STMT_PERFORM:
+ rc = exec_stmt_perform(estate, (PLpgSQL_stmt_perform *) stmt);
+ break;
- case PLPGSQL_STMT_ASSIGN:
- rc = exec_stmt_assign(estate, (PLpgSQL_stmt_assign *) stmt);
- break;
+ case PLPGSQL_STMT_CALL:
+ rc = exec_stmt_call(estate, (PLpgSQL_stmt_call *) stmt);
+ break;
- case PLPGSQL_STMT_PERFORM:
- rc = exec_stmt_perform(estate, (PLpgSQL_stmt_perform *) stmt);
- break;
+ case PLPGSQL_STMT_GETDIAG:
+ rc = exec_stmt_getdiag(estate, (PLpgSQL_stmt_getdiag *) stmt);
+ break;
- case PLPGSQL_STMT_CALL:
- rc = exec_stmt_call(estate, (PLpgSQL_stmt_call *) stmt);
- break;
+ case PLPGSQL_STMT_IF:
+ rc = exec_stmt_if(estate, (PLpgSQL_stmt_if *) stmt);
+ break;
- case PLPGSQL_STMT_GETDIAG:
- rc = exec_stmt_getdiag(estate, (PLpgSQL_stmt_getdiag *) stmt);
- break;
+ case PLPGSQL_STMT_CASE:
+ rc = exec_stmt_case(estate, (PLpgSQL_stmt_case *) stmt);
+ break;
- case PLPGSQL_STMT_IF:
- rc = exec_stmt_if(estate, (PLpgSQL_stmt_if *) stmt);
- break;
+ case PLPGSQL_STMT_LOOP:
+ rc = exec_stmt_loop(estate, (PLpgSQL_stmt_loop *) stmt);
+ break;
- case PLPGSQL_STMT_CASE:
- rc = exec_stmt_case(estate, (PLpgSQL_stmt_case *) stmt);
- break;
+ case PLPGSQL_STMT_WHILE:
+ rc = exec_stmt_while(estate, (PLpgSQL_stmt_while *) stmt);
+ break;
- case PLPGSQL_STMT_LOOP:
- rc = exec_stmt_loop(estate, (PLpgSQL_stmt_loop *) stmt);
- break;
+ case PLPGSQL_STMT_FORI:
+ rc = exec_stmt_fori(estate, (PLpgSQL_stmt_fori *) stmt);
+ break;
- case PLPGSQL_STMT_WHILE:
- rc = exec_stmt_while(estate, (PLpgSQL_stmt_while *) stmt);
- break;
+ case PLPGSQL_STMT_FORS:
+ rc = exec_stmt_fors(estate, (PLpgSQL_stmt_fors *) stmt);
+ break;
- case PLPGSQL_STMT_FORI:
- rc = exec_stmt_fori(estate, (PLpgSQL_stmt_fori *) stmt);
- break;
+ case PLPGSQL_STMT_FORC:
+ rc = exec_stmt_forc(estate, (PLpgSQL_stmt_forc *) stmt);
+ break;
- case PLPGSQL_STMT_FORS:
- rc = exec_stmt_fors(estate, (PLpgSQL_stmt_fors *) stmt);
- break;
+ case PLPGSQL_STMT_FOREACH_A:
+ rc = exec_stmt_foreach_a(estate, (PLpgSQL_stmt_foreach_a *) stmt);
+ break;
- case PLPGSQL_STMT_FORC:
- rc = exec_stmt_forc(estate, (PLpgSQL_stmt_forc *) stmt);
- break;
+ case PLPGSQL_STMT_EXIT:
+ rc = exec_stmt_exit(estate, (PLpgSQL_stmt_exit *) stmt);
+ break;
- case PLPGSQL_STMT_FOREACH_A:
- rc = exec_stmt_foreach_a(estate, (PLpgSQL_stmt_foreach_a *) stmt);
- break;
+ case PLPGSQL_STMT_RETURN:
+ rc = exec_stmt_return(estate, (PLpgSQL_stmt_return *) stmt);
+ break;
- case PLPGSQL_STMT_EXIT:
- rc = exec_stmt_exit(estate, (PLpgSQL_stmt_exit *) stmt);
- break;
+ case PLPGSQL_STMT_RETURN_NEXT:
+ rc = exec_stmt_return_next(estate, (PLpgSQL_stmt_return_next *) stmt);
+ break;
- case PLPGSQL_STMT_RETURN:
- rc = exec_stmt_return(estate, (PLpgSQL_stmt_return *) stmt);
- break;
+ case PLPGSQL_STMT_RETURN_QUERY:
+ rc = exec_stmt_return_query(estate, (PLpgSQL_stmt_return_query *) stmt);
+ break;
- case PLPGSQL_STMT_RETURN_NEXT:
- rc = exec_stmt_return_next(estate, (PLpgSQL_stmt_return_next *) stmt);
- break;
+ case PLPGSQL_STMT_RAISE:
+ rc = exec_stmt_raise(estate, (PLpgSQL_stmt_raise *) stmt);
+ break;
- case PLPGSQL_STMT_RETURN_QUERY:
- rc = exec_stmt_return_query(estate, (PLpgSQL_stmt_return_query *) stmt);
- break;
+ case PLPGSQL_STMT_ASSERT:
+ rc = exec_stmt_assert(estate, (PLpgSQL_stmt_assert *) stmt);
+ break;
- case PLPGSQL_STMT_RAISE:
- rc = exec_stmt_raise(estate, (PLpgSQL_stmt_raise *) stmt);
- break;
+ case PLPGSQL_STMT_EXECSQL:
+ rc = exec_stmt_execsql(estate, (PLpgSQL_stmt_execsql *) stmt);
+ break;
- case PLPGSQL_STMT_ASSERT:
- rc = exec_stmt_assert(estate, (PLpgSQL_stmt_assert *) stmt);
- break;
+ case PLPGSQL_STMT_DYNEXECUTE:
+ rc = exec_stmt_dynexecute(estate, (PLpgSQL_stmt_dynexecute *) stmt);
+ break;
- case PLPGSQL_STMT_EXECSQL:
- rc = exec_stmt_execsql(estate, (PLpgSQL_stmt_execsql *) stmt);
- break;
+ case PLPGSQL_STMT_DYNFORS:
+ rc = exec_stmt_dynfors(estate, (PLpgSQL_stmt_dynfors *) stmt);
+ break;
- case PLPGSQL_STMT_DYNEXECUTE:
- rc = exec_stmt_dynexecute(estate, (PLpgSQL_stmt_dynexecute *) stmt);
- break;
+ case PLPGSQL_STMT_OPEN:
+ rc = exec_stmt_open(estate, (PLpgSQL_stmt_open *) stmt);
+ break;
- case PLPGSQL_STMT_DYNFORS:
- rc = exec_stmt_dynfors(estate, (PLpgSQL_stmt_dynfors *) stmt);
- break;
+ case PLPGSQL_STMT_FETCH:
+ rc = exec_stmt_fetch(estate, (PLpgSQL_stmt_fetch *) stmt);
+ break;
- case PLPGSQL_STMT_OPEN:
- rc = exec_stmt_open(estate, (PLpgSQL_stmt_open *) stmt);
- break;
+ case PLPGSQL_STMT_CLOSE:
+ rc = exec_stmt_close(estate, (PLpgSQL_stmt_close *) stmt);
+ break;
- case PLPGSQL_STMT_FETCH:
- rc = exec_stmt_fetch(estate, (PLpgSQL_stmt_fetch *) stmt);
- break;
+ case PLPGSQL_STMT_COMMIT:
+ rc = exec_stmt_commit(estate, (PLpgSQL_stmt_commit *) stmt);
+ break;
- case PLPGSQL_STMT_CLOSE:
- rc = exec_stmt_close(estate, (PLpgSQL_stmt_close *) stmt);
- break;
+ case PLPGSQL_STMT_ROLLBACK:
+ rc = exec_stmt_rollback(estate, (PLpgSQL_stmt_rollback *) stmt);
+ break;
- case PLPGSQL_STMT_COMMIT:
- rc = exec_stmt_commit(estate, (PLpgSQL_stmt_commit *) stmt);
- break;
+ case PLPGSQL_STMT_SET:
+ rc = exec_stmt_set(estate, (PLpgSQL_stmt_set *) stmt);
+ break;
- case PLPGSQL_STMT_ROLLBACK:
- rc = exec_stmt_rollback(estate, (PLpgSQL_stmt_rollback *) stmt);
- break;
+ default:
+ /* point err_stmt to parent, since this one seems corrupt */
+ estate->err_stmt = save_estmt;
+ elog(ERROR, "unrecognized cmd_type: %d", stmt->cmd_type);
+ rc = -1; /* keep compiler quiet */
+ }
- case PLPGSQL_STMT_SET:
- rc = exec_stmt_set(estate, (PLpgSQL_stmt_set *) stmt);
- break;
+ /* Let the plugin know that we have finished executing this statement */
+ if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->stmt_end)
+ ((*plpgsql_plugin_ptr)->stmt_end) (estate, stmt);
- default:
+ if (rc != PLPGSQL_RC_OK)
+ {
estate->err_stmt = save_estmt;
- elog(ERROR, "unrecognized cmd_type: %d", stmt->cmd_type);
- }
-
- /* Let the plugin know that we have finished executing this statement */
- if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->stmt_end)
- ((*plpgsql_plugin_ptr)->stmt_end) (estate, stmt);
+ return rc;
+ }
+ } /* end of loop over statements */
estate->err_stmt = save_estmt;
-
- return rc;
+ return PLPGSQL_RC_OK;
}
This is the main PostgreSQL git repository.
RSS Atom

AltStyle によって変換されたページ (->オリジナル) /