aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Eisentraut <peter_e@gmx.net>2017-12-15 15:24:10 -0500
committerPeter Eisentraut <peter_e@gmx.net>2018-01-10 10:20:51 -0500
commitb3617cdfbba1b5381e9d1c6bc0839500e8eb7273 (patch)
treea2c29bd9c2b47c1ebea6e0532b8067d55d3c81b4
parentacc67ffd0a8c728b928958e75b76ee544b64c2d8 (diff)
downloadpostgresql-b3617cdfbba1b5381e9d1c6bc0839500e8eb7273.tar.gz
postgresql-b3617cdfbba1b5381e9d1c6bc0839500e8eb7273.zip
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. In the core distribution, this affects PL/Perl and PL/Python, preventing users from manually closing cursors created by spi_query and plpy.cursor, respectively. (PL/Tcl does not currently offer any cursor functionality.) Reviewed-by: Andrew Dunstan <andrew.dunstan@2ndquadrant.com>
-rw-r--r--src/backend/executor/spi.c9
-rw-r--r--src/pl/plpgsql/src/pl_exec.c8
2 files changed, 9 insertions, 8 deletions
diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c
index 995f67d2662..96370513e80 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 d096f242cdc..a326a04fc91 100644
--- a/src/pl/plpgsql/src/pl_exec.c
+++ b/src/pl/plpgsql/src/pl_exec.c
@@ -5258,12 +5258,6 @@ exec_for_query(PLpgSQL_execstate *estate, PLpgSQL_stmt_forq *stmt,
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
* overhead.
@@ -5324,8 +5318,6 @@ loop_exit:
*/
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