Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Move portal pinning from PL/pgSQL to SPI
authorPeter Eisentraut <peter_e@gmx.net>
Fri, 15 Dec 2017 20:24:10 +0000 (15:24 -0500)
committerPeter Eisentraut <peter_e@gmx.net>
Wed, 10 Jan 2018 15:20:51 +0000 (10:20 -0500)
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>
src/backend/executor/spi.c
src/pl/plpgsql/src/pl_exec.c

index 995f67d266259350e6019948788963a74a23f71b..96370513e80d3d85b2436d93c3b6e4c90bdb881e 100644 (file)
@@ -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);
 }
 
index d096f242cdcdb4436db1d3fb6deddf3006025e3e..a326a04fc9172416499c18bd36621171d2e2c5a1 100644 (file)
@@ -5257,12 +5257,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
@@ -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