Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
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)