From f9aaa47cf4e46aac973e532a790ac2099d017523 Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Fri, 15 Dec 2017 15:24:10 -0500 Subject: [PATCH] Move portal pinning from PL/pgSQL to SPI PL/pgSQL "pins" internally generated (unnamed) portals so that user code cannot close them by guessing their names. This logic is also useful in other languages and really for any code. So move that logic into SPI. An unnamed portal obtained through SPI_cursor_open() and related functions is now automatically pinned, and SPI_cursor_close() automatically unpins a portal that is pinned. --- src/backend/executor/spi.c | 9 +++++++++ src/pl/plpgsql/src/pl_exec.c | 8 -------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c index f3da2ddd08..1f0a07ce0b 100644 --- a/src/backend/executor/spi.c +++ b/src/backend/executor/spi.c @@ -1175,6 +1175,12 @@ SPI_cursor_open_internal(const char *name, SPIPlanPtr plan, { /* Use a random nonconflicting name */ portal = CreateNewPortal(); + + /* + * Make sure the portal doesn't get closed by the user statements we + * execute. + */ + PinPortal(portal); } else { @@ -1413,6 +1419,9 @@ SPI_cursor_close(Portal portal) if (!PortalIsValid(portal)) elog(ERROR, "invalid portal in SPI cursor operation"); + if (portal->portalPinned) + UnpinPortal(portal); + PortalDrop(portal, false); } diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c index fa4d573e50..243396abd1 100644 --- a/src/pl/plpgsql/src/pl_exec.c +++ b/src/pl/plpgsql/src/pl_exec.c @@ -5330,12 +5330,6 @@ exec_for_query(PLpgSQL_execstate *estate, PLpgSQL_stmt_forq *stmt, /* Fetch loop variable's datum entry */ var = (PLpgSQL_variable *) estate->datums[stmt->var->dno]; - /* - * Make sure the portal doesn't get closed by the user statements we - * execute. - */ - PinPortal(portal); - /* * Fetch the initial tuple(s). If prefetching is allowed then we grab a * few more rows to avoid multiple trips through executor startup @@ -5450,8 +5444,6 @@ exec_for_query(PLpgSQL_execstate *estate, PLpgSQL_stmt_forq *stmt, */ SPI_freetuptable(tuptab); - UnpinPortal(portal); - /* * Set the FOUND variable to indicate the result of executing the loop * (namely, whether we looped one or more times). This must be set last so -- 2.15.1