Skip to content

Commit 1f902d4

Browse files
committed
Inline plpgsql's exec_stmt() into exec_stmts().
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
1 parent ecd9e9f commit 1f902d4

File tree

1 file changed

+147
-133
lines changed

1 file changed

+147
-133
lines changed

src/pl/plpgsql/src/pl_exec.c

Lines changed: 147 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -260,12 +260,12 @@ static MemoryContext get_stmt_mcontext(PLpgSQL_execstate *estate);
260260
static void push_stmt_mcontext(PLpgSQL_execstate *estate);
261261
static void pop_stmt_mcontext(PLpgSQL_execstate *estate);
262262

263+
static int exec_toplevel_block(PLpgSQL_execstate *estate,
264+
PLpgSQL_stmt_block *block);
263265
static int exec_stmt_block(PLpgSQL_execstate *estate,
264266
PLpgSQL_stmt_block *block);
265267
static int exec_stmts(PLpgSQL_execstate *estate,
266268
List *stmts);
267-
static int exec_stmt(PLpgSQL_execstate *estate,
268-
PLpgSQL_stmt *stmt);
269269
static int exec_stmt_assign(PLpgSQL_execstate *estate,
270270
PLpgSQL_stmt_assign *stmt);
271271
static int exec_stmt_perform(PLpgSQL_execstate *estate,
@@ -599,11 +599,9 @@ plpgsql_exec_function(PLpgSQL_function *func, FunctionCallInfo fcinfo,
599599
* Now call the toplevel block of statements
600600
*/
601601
estate.err_text = NULL;
602-
estate.err_stmt = (PLpgSQL_stmt *) (func->action);
603-
rc = exec_stmt(&estate, (PLpgSQL_stmt *) func->action);
602+
rc = exec_toplevel_block(&estate, func->action);
604603
if (rc != PLPGSQL_RC_RETURN)
605604
{
606-
estate.err_stmt = NULL;
607605
estate.err_text = NULL;
608606
ereport(ERROR,
609607
(errcode(ERRCODE_S_R_E_FUNCTION_EXECUTED_NO_RETURN_STATEMENT),
@@ -613,7 +611,6 @@ plpgsql_exec_function(PLpgSQL_function *func, FunctionCallInfo fcinfo,
613611
/*
614612
* We got a return value - process it
615613
*/
616-
estate.err_stmt = NULL;
617614
estate.err_text = gettext_noop("while casting return value to function's return type");
618615

619616
fcinfo->isnull = estate.retisnull;
@@ -1015,18 +1012,15 @@ plpgsql_exec_trigger(PLpgSQL_function *func,
10151012
* Now call the toplevel block of statements
10161013
*/
10171014
estate.err_text = NULL;
1018-
estate.err_stmt = (PLpgSQL_stmt *) (func->action);
1019-
rc = exec_stmt(&estate, (PLpgSQL_stmt *) func->action);
1015+
rc = exec_toplevel_block(&estate, func->action);
10201016
if (rc != PLPGSQL_RC_RETURN)
10211017
{
1022-
estate.err_stmt = NULL;
10231018
estate.err_text = NULL;
10241019
ereport(ERROR,
10251020
(errcode(ERRCODE_S_R_E_FUNCTION_EXECUTED_NO_RETURN_STATEMENT),
10261021
errmsg("control reached end of trigger procedure without RETURN")));
10271022
}
10281023

1029-
estate.err_stmt = NULL;
10301024
estate.err_text = gettext_noop("during function exit");
10311025

10321026
if (estate.retisset)
@@ -1176,18 +1170,15 @@ plpgsql_exec_event_trigger(PLpgSQL_function *func, EventTriggerData *trigdata)
11761170
* Now call the toplevel block of statements
11771171
*/
11781172
estate.err_text = NULL;
1179-
estate.err_stmt = (PLpgSQL_stmt *) (func->action);
1180-
rc = exec_stmt(&estate, (PLpgSQL_stmt *) func->action);
1173+
rc = exec_toplevel_block(&estate, func->action);
11811174
if (rc != PLPGSQL_RC_RETURN)
11821175
{
1183-
estate.err_stmt = NULL;
11841176
estate.err_text = NULL;
11851177
ereport(ERROR,
11861178
(errcode(ERRCODE_S_R_E_FUNCTION_EXECUTED_NO_RETURN_STATEMENT),
11871179
errmsg("control reached end of trigger procedure without RETURN")));
11881180
}
11891181

1190-
estate.err_stmt = NULL;
11911182
estate.err_text = gettext_noop("during function exit");
11921183

11931184
/*
@@ -1584,6 +1575,40 @@ exception_matches_conditions(ErrorData *edata, PLpgSQL_condition *cond)
15841575
}
15851576

15861577

1578+
/* ----------
1579+
* exec_toplevel_block Execute the toplevel block
1580+
*
1581+
* This is intentionally equivalent to executing exec_stmts() with a
1582+
* list consisting of the one statement. One tiny difference is that
1583+
* we do not bother to save the entry value of estate->err_stmt;
1584+
* that's assumed to be NULL.
1585+
* ----------
1586+
*/
1587+
static int
1588+
exec_toplevel_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
1589+
{
1590+
int rc;
1591+
1592+
estate->err_stmt = (PLpgSQL_stmt *) block;
1593+
1594+
/* Let the plugin know that we are about to execute this statement */
1595+
if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->stmt_beg)
1596+
((*plpgsql_plugin_ptr)->stmt_beg) (estate, (PLpgSQL_stmt *) block);
1597+
1598+
CHECK_FOR_INTERRUPTS();
1599+
1600+
rc = exec_stmt_block(estate, block);
1601+
1602+
/* Let the plugin know that we have finished executing this statement */
1603+
if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->stmt_end)
1604+
((*plpgsql_plugin_ptr)->stmt_end) (estate, (PLpgSQL_stmt *) block);
1605+
1606+
estate->err_stmt = NULL;
1607+
1608+
return rc;
1609+
}
1610+
1611+
15871612
/* ----------
15881613
* exec_stmt_block Execute a block of statements
15891614
* ----------
@@ -1917,6 +1942,7 @@ exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
19171942
static int
19181943
exec_stmts(PLpgSQL_execstate *estate, List *stmts)
19191944
{
1945+
PLpgSQL_stmt *save_estmt = estate->err_stmt;
19201946
ListCell *s;
19211947

19221948
if (stmts == NIL)
@@ -1933,162 +1959,150 @@ exec_stmts(PLpgSQL_execstate *estate, List *stmts)
19331959
foreach(s, stmts)
19341960
{
19351961
PLpgSQL_stmt *stmt = (PLpgSQL_stmt *) lfirst(s);
1936-
int rc = exec_stmt(estate, stmt);
1937-
1938-
if (rc != PLPGSQL_RC_OK)
1939-
return rc;
1940-
}
1962+
int rc;
19411963

1942-
return PLPGSQL_RC_OK;
1943-
}
1964+
estate->err_stmt = stmt;
19441965

1966+
/* Let the plugin know that we are about to execute this statement */
1967+
if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->stmt_beg)
1968+
((*plpgsql_plugin_ptr)->stmt_beg) (estate, stmt);
19451969

1946-
/* ----------
1947-
* exec_stmt Distribute one statement to the statements
1948-
* type specific execution function.
1949-
* ----------
1950-
*/
1951-
static int
1952-
exec_stmt(PLpgSQL_execstate *estate, PLpgSQL_stmt *stmt)
1953-
{
1954-
PLpgSQL_stmt *save_estmt;
1955-
int rc = -1;
1956-
1957-
save_estmt = estate->err_stmt;
1958-
estate->err_stmt = stmt;
1970+
CHECK_FOR_INTERRUPTS();
19591971

1960-
/* Let the plugin know that we are about to execute this statement */
1961-
if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->stmt_beg)
1962-
((*plpgsql_plugin_ptr)->stmt_beg) (estate, stmt);
1972+
switch (stmt->cmd_type)
1973+
{
1974+
case PLPGSQL_STMT_BLOCK:
1975+
rc = exec_stmt_block(estate, (PLpgSQL_stmt_block *) stmt);
1976+
break;
19631977

1964-
CHECK_FOR_INTERRUPTS();
1978+
case PLPGSQL_STMT_ASSIGN:
1979+
rc = exec_stmt_assign(estate, (PLpgSQL_stmt_assign *) stmt);
1980+
break;
19651981

1966-
switch (stmt->cmd_type)
1967-
{
1968-
case PLPGSQL_STMT_BLOCK:
1969-
rc = exec_stmt_block(estate, (PLpgSQL_stmt_block *) stmt);
1970-
break;
1982+
case PLPGSQL_STMT_PERFORM:
1983+
rc = exec_stmt_perform(estate, (PLpgSQL_stmt_perform *) stmt);
1984+
break;
19711985

1972-
case PLPGSQL_STMT_ASSIGN:
1973-
rc = exec_stmt_assign(estate, (PLpgSQL_stmt_assign *) stmt);
1974-
break;
1986+
case PLPGSQL_STMT_CALL:
1987+
rc = exec_stmt_call(estate, (PLpgSQL_stmt_call *) stmt);
1988+
break;
19751989

1976-
case PLPGSQL_STMT_PERFORM:
1977-
rc = exec_stmt_perform(estate, (PLpgSQL_stmt_perform *) stmt);
1978-
break;
1990+
case PLPGSQL_STMT_GETDIAG:
1991+
rc = exec_stmt_getdiag(estate, (PLpgSQL_stmt_getdiag *) stmt);
1992+
break;
19791993

1980-
case PLPGSQL_STMT_CALL:
1981-
rc = exec_stmt_call(estate, (PLpgSQL_stmt_call *) stmt);
1982-
break;
1994+
case PLPGSQL_STMT_IF:
1995+
rc = exec_stmt_if(estate, (PLpgSQL_stmt_if *) stmt);
1996+
break;
19831997

1984-
case PLPGSQL_STMT_GETDIAG:
1985-
rc = exec_stmt_getdiag(estate, (PLpgSQL_stmt_getdiag *) stmt);
1986-
break;
1998+
case PLPGSQL_STMT_CASE:
1999+
rc = exec_stmt_case(estate, (PLpgSQL_stmt_case *) stmt);
2000+
break;
19872001

1988-
case PLPGSQL_STMT_IF:
1989-
rc = exec_stmt_if(estate, (PLpgSQL_stmt_if *) stmt);
1990-
break;
2002+
case PLPGSQL_STMT_LOOP:
2003+
rc = exec_stmt_loop(estate, (PLpgSQL_stmt_loop *) stmt);
2004+
break;
19912005

1992-
case PLPGSQL_STMT_CASE:
1993-
rc = exec_stmt_case(estate, (PLpgSQL_stmt_case *) stmt);
1994-
break;
2006+
case PLPGSQL_STMT_WHILE:
2007+
rc = exec_stmt_while(estate, (PLpgSQL_stmt_while *) stmt);
2008+
break;
19952009

1996-
case PLPGSQL_STMT_LOOP:
1997-
rc = exec_stmt_loop(estate, (PLpgSQL_stmt_loop *) stmt);
1998-
break;
2010+
case PLPGSQL_STMT_FORI:
2011+
rc = exec_stmt_fori(estate, (PLpgSQL_stmt_fori *) stmt);
2012+
break;
19992013

2000-
case PLPGSQL_STMT_WHILE:
2001-
rc = exec_stmt_while(estate, (PLpgSQL_stmt_while *) stmt);
2002-
break;
2014+
case PLPGSQL_STMT_FORS:
2015+
rc = exec_stmt_fors(estate, (PLpgSQL_stmt_fors *) stmt);
2016+
break;
20032017

2004-
case PLPGSQL_STMT_FORI:
2005-
rc = exec_stmt_fori(estate, (PLpgSQL_stmt_fori *) stmt);
2006-
break;
2018+
case PLPGSQL_STMT_FORC:
2019+
rc = exec_stmt_forc(estate, (PLpgSQL_stmt_forc *) stmt);
2020+
break;
20072021

2008-
case PLPGSQL_STMT_FORS:
2009-
rc = exec_stmt_fors(estate, (PLpgSQL_stmt_fors *) stmt);
2010-
break;
2022+
case PLPGSQL_STMT_FOREACH_A:
2023+
rc = exec_stmt_foreach_a(estate, (PLpgSQL_stmt_foreach_a *) stmt);
2024+
break;
20112025

2012-
case PLPGSQL_STMT_FORC:
2013-
rc = exec_stmt_forc(estate, (PLpgSQL_stmt_forc *) stmt);
2014-
break;
2026+
case PLPGSQL_STMT_EXIT:
2027+
rc = exec_stmt_exit(estate, (PLpgSQL_stmt_exit *) stmt);
2028+
break;
20152029

2016-
case PLPGSQL_STMT_FOREACH_A:
2017-
rc = exec_stmt_foreach_a(estate, (PLpgSQL_stmt_foreach_a *) stmt);
2018-
break;
2030+
case PLPGSQL_STMT_RETURN:
2031+
rc = exec_stmt_return(estate, (PLpgSQL_stmt_return *) stmt);
2032+
break;
20192033

2020-
case PLPGSQL_STMT_EXIT:
2021-
rc = exec_stmt_exit(estate, (PLpgSQL_stmt_exit *) stmt);
2022-
break;
2034+
case PLPGSQL_STMT_RETURN_NEXT:
2035+
rc = exec_stmt_return_next(estate, (PLpgSQL_stmt_return_next *) stmt);
2036+
break;
20232037

2024-
case PLPGSQL_STMT_RETURN:
2025-
rc = exec_stmt_return(estate, (PLpgSQL_stmt_return *) stmt);
2026-
break;
2038+
case PLPGSQL_STMT_RETURN_QUERY:
2039+
rc = exec_stmt_return_query(estate, (PLpgSQL_stmt_return_query *) stmt);
2040+
break;
20272041

2028-
case PLPGSQL_STMT_RETURN_NEXT:
2029-
rc = exec_stmt_return_next(estate, (PLpgSQL_stmt_return_next *) stmt);
2030-
break;
2042+
case PLPGSQL_STMT_RAISE:
2043+
rc = exec_stmt_raise(estate, (PLpgSQL_stmt_raise *) stmt);
2044+
break;
20312045

2032-
case PLPGSQL_STMT_RETURN_QUERY:
2033-
rc = exec_stmt_return_query(estate, (PLpgSQL_stmt_return_query *) stmt);
2034-
break;
2046+
case PLPGSQL_STMT_ASSERT:
2047+
rc = exec_stmt_assert(estate, (PLpgSQL_stmt_assert *) stmt);
2048+
break;
20352049

2036-
case PLPGSQL_STMT_RAISE:
2037-
rc = exec_stmt_raise(estate, (PLpgSQL_stmt_raise *) stmt);
2038-
break;
2050+
case PLPGSQL_STMT_EXECSQL:
2051+
rc = exec_stmt_execsql(estate, (PLpgSQL_stmt_execsql *) stmt);
2052+
break;
20392053

2040-
case PLPGSQL_STMT_ASSERT:
2041-
rc = exec_stmt_assert(estate, (PLpgSQL_stmt_assert *) stmt);
2042-
break;
2054+
case PLPGSQL_STMT_DYNEXECUTE:
2055+
rc = exec_stmt_dynexecute(estate, (PLpgSQL_stmt_dynexecute *) stmt);
2056+
break;
20432057

2044-
case PLPGSQL_STMT_EXECSQL:
2045-
rc = exec_stmt_execsql(estate, (PLpgSQL_stmt_execsql *) stmt);
2046-
break;
2058+
case PLPGSQL_STMT_DYNFORS:
2059+
rc = exec_stmt_dynfors(estate, (PLpgSQL_stmt_dynfors *) stmt);
2060+
break;
20472061

2048-
case PLPGSQL_STMT_DYNEXECUTE:
2049-
rc = exec_stmt_dynexecute(estate, (PLpgSQL_stmt_dynexecute *) stmt);
2050-
break;
2062+
case PLPGSQL_STMT_OPEN:
2063+
rc = exec_stmt_open(estate, (PLpgSQL_stmt_open *) stmt);
2064+
break;
20512065

2052-
case PLPGSQL_STMT_DYNFORS:
2053-
rc = exec_stmt_dynfors(estate, (PLpgSQL_stmt_dynfors *) stmt);
2054-
break;
2066+
case PLPGSQL_STMT_FETCH:
2067+
rc = exec_stmt_fetch(estate, (PLpgSQL_stmt_fetch *) stmt);
2068+
break;
20552069

2056-
case PLPGSQL_STMT_OPEN:
2057-
rc = exec_stmt_open(estate, (PLpgSQL_stmt_open *) stmt);
2058-
break;
2070+
case PLPGSQL_STMT_CLOSE:
2071+
rc = exec_stmt_close(estate, (PLpgSQL_stmt_close *) stmt);
2072+
break;
20592073

2060-
case PLPGSQL_STMT_FETCH:
2061-
rc = exec_stmt_fetch(estate, (PLpgSQL_stmt_fetch *) stmt);
2062-
break;
2074+
case PLPGSQL_STMT_COMMIT:
2075+
rc = exec_stmt_commit(estate, (PLpgSQL_stmt_commit *) stmt);
2076+
break;
20632077

2064-
case PLPGSQL_STMT_CLOSE:
2065-
rc = exec_stmt_close(estate, (PLpgSQL_stmt_close *) stmt);
2066-
break;
2078+
case PLPGSQL_STMT_ROLLBACK:
2079+
rc = exec_stmt_rollback(estate, (PLpgSQL_stmt_rollback *) stmt);
2080+
break;
20672081

2068-
case PLPGSQL_STMT_COMMIT:
2069-
rc = exec_stmt_commit(estate, (PLpgSQL_stmt_commit *) stmt);
2070-
break;
2082+
case PLPGSQL_STMT_SET:
2083+
rc = exec_stmt_set(estate, (PLpgSQL_stmt_set *) stmt);
2084+
break;
20712085

2072-
case PLPGSQL_STMT_ROLLBACK:
2073-
rc = exec_stmt_rollback(estate, (PLpgSQL_stmt_rollback *) stmt);
2074-
break;
2086+
default:
2087+
/* point err_stmt to parent, since this one seems corrupt */
2088+
estate->err_stmt = save_estmt;
2089+
elog(ERROR, "unrecognized cmd_type: %d", stmt->cmd_type);
2090+
rc = -1; /* keep compiler quiet */
2091+
}
20752092

2076-
case PLPGSQL_STMT_SET:
2077-
rc = exec_stmt_set(estate, (PLpgSQL_stmt_set *) stmt);
2078-
break;
2093+
/* Let the plugin know that we have finished executing this statement */
2094+
if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->stmt_end)
2095+
((*plpgsql_plugin_ptr)->stmt_end) (estate, stmt);
20792096

2080-
default:
2097+
if (rc != PLPGSQL_RC_OK)
2098+
{
20812099
estate->err_stmt = save_estmt;
2082-
elog(ERROR, "unrecognized cmd_type: %d", stmt->cmd_type);
2083-
}
2084-
2085-
/* Let the plugin know that we have finished executing this statement */
2086-
if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->stmt_end)
2087-
((*plpgsql_plugin_ptr)->stmt_end) (estate, stmt);
2100+
return rc;
2101+
}
2102+
} /* end of loop over statements */
20882103

20892104
estate->err_stmt = save_estmt;
2090-
2091-
return rc;
2105+
return PLPGSQL_RC_OK;
20922106
}
20932107

20942108

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy