* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/mmgr/portalmem.c,v 1.76.4.2 2005/04/11 19:51:31 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/mmgr/portalmem.c,v 1.76.4.3 2010/07/05 09:27:49 heikki Exp $
*
*-------------------------------------------------------------------------
*/
MemoryContextSwitchTo(oldcxt);
}
+/*
+ * 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.
{
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
continue;
}
+ /*
+ * 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).
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);
}
}
* 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.54.4.1 2005/04/11 19:51:32 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/utils/portal.h,v 1.54.4.2 2010/07/05 09:27:49 heikki Exp $
*
*-------------------------------------------------------------------------
*/
/* 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 */
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);
* procedural language
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.127.4.8 2010/02/12 19:38:15 tgl Exp $
+ * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.127.4.9 2010/07/05 09:27:49 heikki Exp $
*
* This software is copyrighted by Jan Wieck - Hamburg.
*
/*
* 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;
* (This code should match the code after the loop.)
*/
SPI_freetuptable(tuptab);
+ UnpinPortal(portal);
SPI_cursor_close(portal);
exec_set_found(estate, found);
/*
* Close the implicit cursor
*/
+ UnpinPortal(portal);
SPI_cursor_close(portal);
/*
pfree(querystr);
SPI_freeplan(plan);
+ /*
+ * Make sure the portal doesn't get closed by the user statements
+ * we execute.
+ */
+ PinPortal(portal);
+
/*
* Fetch the initial 10 tuples
*/
* (This code should match the code after the loop.)
*/
SPI_freetuptable(tuptab);
+ UnpinPortal(portal);
SPI_cursor_close(portal);
exec_set_found(estate, found);
/*
* Close the implicit cursor
*/
+ UnpinPortal(portal);
SPI_cursor_close(portal);
/*