aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/mmgr/portalmem.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/utils/mmgr/portalmem.c')
-rw-r--r--src/backend/utils/mmgr/portalmem.c116
1 files changed, 93 insertions, 23 deletions
diff --git a/src/backend/utils/mmgr/portalmem.c b/src/backend/utils/mmgr/portalmem.c
index 66ee72718cf..e6486d4b16d 100644
--- a/src/backend/utils/mmgr/portalmem.c
+++ b/src/backend/utils/mmgr/portalmem.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/mmgr/portalmem.c,v 1.53 2003/03/11 19:40:23 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/mmgr/portalmem.c,v 1.54 2003/03/27 16:51:29 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -20,8 +20,8 @@
* "PortalData" structure, plans the query and then stores the query
* in the portal without executing it. Later, when the backend
* sees a
- * fetch 1 from FOO
- * the system looks up the portal named "FOO" in the portal table,
+ * fetch 1 from foo
+ * the system looks up the portal named "foo" in the portal table,
* gets the planned query and then calls the executor with a count
* of 1. The executor then runs the query and returns a single
* tuple. The problem is that we have to hold onto the state of the
@@ -38,7 +38,6 @@
#include "utils/memutils.h"
#include "utils/portal.h"
-
/*
* estimate of the maximum number of open portals a user would have,
* used in initially sizing the PortalHashTable in EnablePortalManager()
@@ -131,8 +130,8 @@ EnablePortalManager(void)
ctl.entrysize = sizeof(PortalHashEnt);
/*
- * use PORTALS_PER_USER, defined in utils/portal.h as a guess of how
- * many hash table entries to create, initially
+ * use PORTALS_PER_USER as a guess of how many hash table entries to
+ * create, initially
*/
PortalHashTable = hash_create("Portal hash", PORTALS_PER_USER,
&ctl, HASH_ELEM);
@@ -157,7 +156,9 @@ GetPortalByName(const char *name)
/*
* PortalSetQuery
- * Attaches a "query" to portal.
+ * Attaches a "query" to the specified portal. Note that in the
+ * case of DECLARE CURSOR, some Portal options have already been
+ * set based upon the parsetree of the original DECLARE statement.
*/
void
PortalSetQuery(Portal portal,
@@ -166,9 +167,25 @@ PortalSetQuery(Portal portal,
{
AssertArg(PortalIsValid(portal));
+ /*
+ * If the user didn't specify a SCROLL type, allow or disallow
+ * scrolling based on whether it would require any additional
+ * runtime overhead to do so.
+ */
+ if (portal->scrollType == DEFAULT_SCROLL)
+ {
+ bool backwardPlan;
+
+ backwardPlan = ExecSupportsBackwardScan(queryDesc->plantree);
+
+ if (backwardPlan)
+ portal->scrollType = ENABLE_SCROLL;
+ else
+ portal->scrollType = DISABLE_SCROLL;
+ }
+
portal->queryDesc = queryDesc;
portal->cleanup = cleanup;
- portal->backwardOK = ExecSupportsBackwardScan(queryDesc->plantree);
portal->atStart = true;
portal->atEnd = false; /* allow fetches */
portal->portalPos = 0;
@@ -179,10 +196,8 @@ PortalSetQuery(Portal portal,
* CreatePortal
* Returns a new portal given a name.
*
- * Exceptions:
- * BadState if called when disabled.
- * BadArg if portal name is invalid.
- * "WARNING" if portal name is in use (existing portal is returned!)
+ * An elog(WARNING) is emitted if portal name is in use (existing
+ * portal is returned!)
*/
Portal
CreatePortal(const char *name)
@@ -214,7 +229,11 @@ CreatePortal(const char *name)
/* initialize portal query */
portal->queryDesc = NULL;
portal->cleanup = NULL;
- portal->backwardOK = false;
+ portal->scrollType = DEFAULT_SCROLL;
+ portal->holdOpen = false;
+ portal->holdStore = NULL;
+ portal->holdContext = NULL;
+ portal->createXact = GetCurrentTransactionId();
portal->atStart = true;
portal->atEnd = true; /* disallow fetches until query is set */
portal->portalPos = 0;
@@ -228,17 +247,47 @@ CreatePortal(const char *name)
/*
* PortalDrop
- * Destroys portal.
+ * Destroy the portal.
*
- * Exceptions:
- * BadState if called when disabled.
- * BadArg if portal is invalid.
+ * keepHoldable: if true, holdable portals should not be removed by
+ * this function. More specifically, invoking this function with
+ * keepHoldable = true on a holdable portal prepares the portal for
+ * access outside of its creating transaction.
*/
void
-PortalDrop(Portal portal)
+PortalDrop(Portal portal, bool persistHoldable)
{
AssertArg(PortalIsValid(portal));
+ if (portal->holdOpen && persistHoldable)
+ {
+ /*
+ * We're "dropping" a holdable portal, but what we really need
+ * to do is prepare the portal for access outside of its
+ * creating transaction.
+ */
+
+ /*
+ * Create the memory context that is used for storage of
+ * long-term (cross transaction) data needed by the holdable
+ * portal.
+ */
+ portal->holdContext =
+ AllocSetContextCreate(PortalMemory,
+ "PortalHeapMemory",
+ ALLOCSET_DEFAULT_MINSIZE,
+ ALLOCSET_DEFAULT_INITSIZE,
+ ALLOCSET_DEFAULT_MAXSIZE);
+
+ /*
+ * Note that PersistHoldablePortal() releases any resources used
+ * by the portal that are local to the creating txn.
+ */
+ PersistHoldablePortal(portal);
+
+ return;
+ }
+
/* remove portal from hash table */
PortalHashTableDelete(portal);
@@ -246,8 +295,20 @@ PortalDrop(Portal portal)
if (PointerIsValid(portal->cleanup))
(*portal->cleanup) (portal);
- /* release subsidiary storage */
- MemoryContextDelete(PortalGetHeapMemory(portal));
+ /*
+ * delete short-term memory context; in the case of a holdable
+ * portal, this has already been done
+ */
+ if (PortalGetHeapMemory(portal))
+ MemoryContextDelete(PortalGetHeapMemory(portal));
+
+ /*
+ * delete long-term memory context; in the case of a non-holdable
+ * portal, this context has never been created, so we don't need to
+ * do anything
+ */
+ if (portal->holdContext)
+ MemoryContextDelete(portal->holdContext);
/* release name and portal data (both are in PortalMemory) */
pfree(portal->name);
@@ -255,7 +316,12 @@ PortalDrop(Portal portal)
}
/*
- * Destroy all portals created in the current transaction (ie, all of them).
+ * Cleanup the portals created in the current transaction. If the
+ * transaction was aborted, all the portals created in this transaction
+ * should be removed. If the transaction was successfully committed, any
+ * holdable cursors created in this transaction need to be kept
+ * open. Only cursors created in the current transaction should be
+ * removed in this fashion.
*
* XXX This assumes that portals can be deleted in a random order, ie,
* no portal has a reference to any other (at least not one that will be
@@ -264,13 +330,17 @@ PortalDrop(Portal portal)
* references...
*/
void
-AtEOXact_portals(void)
+AtEOXact_portals(bool isCommit)
{
HASH_SEQ_STATUS status;
PortalHashEnt *hentry;
+ TransactionId xact = GetCurrentTransactionId();
hash_seq_init(&status, PortalHashTable);
while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL)
- PortalDrop(hentry->portal);
+ {
+ if (hentry->portal->createXact == xact)
+ PortalDrop(hentry->portal, isCommit);
+ }
}