diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/backend/utils/mmgr/portalmem.c | 54 | ||||
-rw-r--r-- | src/include/utils/portal.h | 5 | ||||
-rw-r--r-- | src/pl/plpgsql/src/pl_exec.c | 16 |
3 files changed, 67 insertions, 8 deletions
diff --git a/src/backend/utils/mmgr/portalmem.c b/src/backend/utils/mmgr/portalmem.c index 5f599699665..303c98e6286 100644 --- a/src/backend/utils/mmgr/portalmem.c +++ b/src/backend/utils/mmgr/portalmem.c @@ -12,7 +12,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/mmgr/portalmem.c,v 1.82.2.2 2007/04/26 23:25:09 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/mmgr/portalmem.c,v 1.82.2.3 2010/07/05 09:27:42 heikki Exp $ * *------------------------------------------------------------------------- */ @@ -292,6 +292,28 @@ PortalCreateHoldStore(Portal portal) } /* + * PinPortal + * Protect a portal from dropping. + */ +void +PinPortal(Portal portal) +{ + if (portal->portalPinned) + elog(ERROR, "portal already pinned"); + + portal->portalPinned = true; +} + +void +UnpinPortal(Portal portal) +{ + if (!portal->portalPinned) + elog(ERROR, "portal not pinned"); + + portal->portalPinned = false; +} + +/* * PortalDrop * Destroy the portal. */ @@ -300,9 +322,16 @@ PortalDrop(Portal portal, bool isTopCommit) { AssertArg(PortalIsValid(portal)); - /* Not sure if this case can validly happen or not... */ - if (portal->status == PORTAL_ACTIVE) - elog(ERROR, "cannot drop active portal"); + /* + * Don't allow dropping a pinned portal, it's still needed by whoever + * pinned it. Not sure if the PORTAL_ACTIVE case can validly happen or + * not... + */ + if (portal->portalPinned || + portal->status == PORTAL_ACTIVE) + ereport(ERROR, + (errcode(ERRCODE_INVALID_CURSOR_STATE), + errmsg("cannot drop active portal \"%s\"", portal->name))); /* * Remove portal from hash table. Because we do this first, we will not @@ -539,6 +568,13 @@ AtCommit_Portals(void) } /* + * There should be no pinned portals anymore. Complain if someone + * leaked one. + */ + if (portal->portalPinned) + elog(ERROR, "cannot commit while a portal is pinned"); + + /* * Do nothing to cursors held over from a previous transaction * (including holdable ones just frozen by CommitHoldablePortals). */ @@ -625,7 +661,15 @@ AtCleanup_Portals(void) continue; } - /* Else zap it. */ + /* + * If a portal is still pinned, forcibly unpin it. PortalDrop will + * not let us drop the portal otherwise. Whoever pinned the portal + * was interrupted by the abort too and won't try to use it anymore. + */ + if (portal->portalPinned) + portal->portalPinned = false; + + /* Zap it. */ PortalDrop(portal, false); } } diff --git a/src/include/utils/portal.h b/src/include/utils/portal.h index 758592525ff..1d8aa280d1a 100644 --- a/src/include/utils/portal.h +++ b/src/include/utils/portal.h @@ -39,7 +39,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/utils/portal.h,v 1.57 2005/10/15 02:49:46 momjian Exp $ + * $PostgreSQL: pgsql/src/include/utils/portal.h,v 1.57.2.1 2010/07/05 09:27:42 heikki Exp $ * *------------------------------------------------------------------------- */ @@ -136,6 +136,7 @@ typedef struct PortalData /* Status data */ PortalStatus status; /* see above */ bool portalUtilReady; /* PortalRunUtility complete? */ + bool portalPinned; /* a pinned portal can't be dropped */ /* If not NULL, Executor is active; call ExecutorEnd eventually: */ QueryDesc *queryDesc; /* info needed for executor invocation */ @@ -197,6 +198,8 @@ extern void AtSubAbort_Portals(SubTransactionId mySubid, extern void AtSubCleanup_Portals(SubTransactionId mySubid); extern Portal CreatePortal(const char *name, bool allowDup, bool dupSilent); extern Portal CreateNewPortal(void); +extern void PinPortal(Portal portal); +extern void UnpinPortal(Portal portal); extern void PortalDrop(Portal portal, bool isTopCommit); extern void DropDependentPortals(MemoryContext queryContext); extern Portal GetPortalByName(const char *name); diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c index 3064c906bd5..05f84580c5e 100644 --- a/src/pl/plpgsql/src/pl_exec.c +++ b/src/pl/plpgsql/src/pl_exec.c @@ -3,7 +3,7 @@ * procedural language * * IDENTIFICATION - * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.154.2.10 2010/02/12 19:38:08 tgl Exp $ + * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.154.2.11 2010/07/05 09:27:42 heikki Exp $ * * This software is copyrighted by Jan Wieck - Hamburg. * @@ -1547,9 +1547,11 @@ exec_stmt_fors(PLpgSQL_execstate *estate, PLpgSQL_stmt_fors *stmt) /* * Open the implicit cursor for the statement and fetch the initial 10 - * rows. + * rows. Pin the portal to make sure it doesn't get closed by the user + * statements we execute. */ exec_run_select(estate, stmt->query, 0, &portal); + PinPortal(portal); SPI_cursor_fetch(portal, true, 10); tuptab = SPI_tuptable; @@ -1631,6 +1633,7 @@ exec_stmt_fors(PLpgSQL_execstate *estate, PLpgSQL_stmt_fors *stmt) * code should match the code after the loop.) */ SPI_freetuptable(tuptab); + UnpinPortal(portal); SPI_cursor_close(portal); exec_set_found(estate, found); @@ -1656,6 +1659,7 @@ exec_stmt_fors(PLpgSQL_execstate *estate, PLpgSQL_stmt_fors *stmt) /* * Close the implicit cursor */ + UnpinPortal(portal); SPI_cursor_close(portal); /* @@ -2581,6 +2585,12 @@ exec_stmt_dynfors(PLpgSQL_execstate *estate, PLpgSQL_stmt_dynfors *stmt) SPI_freeplan(plan); /* + * Make sure the portal doesn't get closed by the user statements + * we execute. + */ + PinPortal(portal); + + /* * Fetch the initial 10 tuples */ SPI_cursor_fetch(portal, true, 10); @@ -2663,6 +2673,7 @@ exec_stmt_dynfors(PLpgSQL_execstate *estate, PLpgSQL_stmt_dynfors *stmt) * code should match the code after the loop.) */ SPI_freetuptable(tuptab); + UnpinPortal(portal); SPI_cursor_close(portal); exec_set_found(estate, found); @@ -2688,6 +2699,7 @@ exec_stmt_dynfors(PLpgSQL_execstate *estate, PLpgSQL_stmt_dynfors *stmt) /* * Close the implicit cursor */ + UnpinPortal(portal); SPI_cursor_close(portal); /* |