aboutsummaryrefslogtreecommitdiff
path: root/src/backend/commands/portalcmds.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/commands/portalcmds.c')
-rw-r--r--src/backend/commands/portalcmds.c157
1 files changed, 92 insertions, 65 deletions
diff --git a/src/backend/commands/portalcmds.c b/src/backend/commands/portalcmds.c
index b176a6c0c7b..509d9e0dfa1 100644
--- a/src/backend/commands/portalcmds.c
+++ b/src/backend/commands/portalcmds.c
@@ -14,7 +14,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/portalcmds.c,v 1.29 2004/07/17 03:28:47 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/portalcmds.c,v 1.30 2004/07/31 00:45:31 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -259,8 +259,18 @@ PortalCleanup(Portal portal)
/* We must make the portal's resource owner current */
saveResourceOwner = CurrentResourceOwner;
- CurrentResourceOwner = portal->resowner;
- ExecutorEnd(queryDesc);
+ PG_TRY();
+ {
+ CurrentResourceOwner = portal->resowner;
+ ExecutorEnd(queryDesc);
+ }
+ PG_CATCH();
+ {
+ /* Ensure CurrentResourceOwner is restored on error */
+ CurrentResourceOwner = saveResourceOwner;
+ PG_RE_THROW();
+ }
+ PG_END_TRY();
CurrentResourceOwner = saveResourceOwner;
}
}
@@ -317,86 +327,95 @@ PersistHoldablePortal(Portal portal)
portal->status = PORTAL_ACTIVE;
/*
- * Set global portal context pointers.
+ * Set up global portal context pointers.
*/
saveActivePortal = ActivePortal;
- ActivePortal = portal;
saveResourceOwner = CurrentResourceOwner;
- CurrentResourceOwner = portal->resowner;
savePortalContext = PortalContext;
- PortalContext = PortalGetHeapMemory(portal);
saveQueryContext = QueryContext;
- QueryContext = portal->queryContext;
+ PG_TRY();
+ {
+ ActivePortal = portal;
+ CurrentResourceOwner = portal->resowner;
+ PortalContext = PortalGetHeapMemory(portal);
+ QueryContext = portal->queryContext;
+
+ MemoryContextSwitchTo(PortalContext);
+
+ /*
+ * Rewind the executor: we need to store the entire result set in the
+ * tuplestore, so that subsequent backward FETCHs can be processed.
+ */
+ ExecutorRewind(queryDesc);
+
+ /* Change the destination to output to the tuplestore */
+ queryDesc->dest = CreateDestReceiver(Tuplestore, portal);
+
+ /* Fetch the result set into the tuplestore */
+ ExecutorRun(queryDesc, ForwardScanDirection, 0L);
+
+ (*queryDesc->dest->rDestroy) (queryDesc->dest);
+ queryDesc->dest = NULL;
+
+ /*
+ * Now shut down the inner executor.
+ */
+ portal->queryDesc = NULL; /* prevent double shutdown */
+ ExecutorEnd(queryDesc);
+
+ /*
+ * Reset the position in the result set: ideally, this could be
+ * implemented by just skipping straight to the tuple # that we need
+ * to be at, but the tuplestore API doesn't support that. So we start
+ * at the beginning of the tuplestore and iterate through it until we
+ * reach where we need to be. FIXME someday?
+ */
+ MemoryContextSwitchTo(portal->holdContext);
+
+ if (!portal->atEnd)
+ {
+ long store_pos;
- MemoryContextSwitchTo(PortalContext);
+ if (portal->posOverflow) /* oops, cannot trust portalPos */
+ ereport(ERROR,
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("could not reposition held cursor")));
- /*
- * Rewind the executor: we need to store the entire result set in the
- * tuplestore, so that subsequent backward FETCHs can be processed.
- */
- ExecutorRewind(queryDesc);
+ tuplestore_rescan(portal->holdStore);
- /* Change the destination to output to the tuplestore */
- queryDesc->dest = CreateDestReceiver(Tuplestore, portal);
+ for (store_pos = 0; store_pos < portal->portalPos; store_pos++)
+ {
+ HeapTuple tup;
+ bool should_free;
- /* Fetch the result set into the tuplestore */
- ExecutorRun(queryDesc, ForwardScanDirection, 0L);
+ tup = tuplestore_gettuple(portal->holdStore, true,
+ &should_free);
- (*queryDesc->dest->rDestroy) (queryDesc->dest);
- queryDesc->dest = NULL;
+ if (tup == NULL)
+ elog(ERROR, "unexpected end of tuple stream");
- /*
- * Now shut down the inner executor.
- */
- portal->queryDesc = NULL; /* prevent double shutdown */
- ExecutorEnd(queryDesc);
-
- /*
- * Reset the position in the result set: ideally, this could be
- * implemented by just skipping straight to the tuple # that we need
- * to be at, but the tuplestore API doesn't support that. So we start
- * at the beginning of the tuplestore and iterate through it until we
- * reach where we need to be. FIXME someday?
- */
- MemoryContextSwitchTo(portal->holdContext);
-
- if (!portal->atEnd)
+ if (should_free)
+ pfree(tup);
+ }
+ }
+ }
+ PG_CATCH();
{
- long store_pos;
-
- if (portal->posOverflow) /* oops, cannot trust portalPos */
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("could not reposition held cursor")));
-
- tuplestore_rescan(portal->holdStore);
-
- for (store_pos = 0; store_pos < portal->portalPos; store_pos++)
- {
- HeapTuple tup;
- bool should_free;
-
- tup = tuplestore_gettuple(portal->holdStore, true,
- &should_free);
+ /* Uncaught error while executing portal: mark it dead */
+ portal->status = PORTAL_FAILED;
- if (tup == NULL)
- elog(ERROR, "unexpected end of tuple stream");
+ /* Restore global vars and propagate error */
+ ActivePortal = saveActivePortal;
+ CurrentResourceOwner = saveResourceOwner;
+ PortalContext = savePortalContext;
+ QueryContext = saveQueryContext;
- if (should_free)
- pfree(tup);
- }
+ PG_RE_THROW();
}
+ PG_END_TRY();
MemoryContextSwitchTo(oldcxt);
- /*
- * We can now release any subsidiary memory of the portal's heap
- * context; we'll never use it again. The executor already dropped
- * its context, but this will clean up anything that glommed onto the
- * portal's heap via PortalContext.
- */
- MemoryContextDeleteChildren(PortalGetHeapMemory(portal));
-
/* Mark portal not active */
portal->status = PORTAL_READY;
@@ -404,4 +423,12 @@ PersistHoldablePortal(Portal portal)
CurrentResourceOwner = saveResourceOwner;
PortalContext = savePortalContext;
QueryContext = saveQueryContext;
+
+ /*
+ * We can now release any subsidiary memory of the portal's heap
+ * context; we'll never use it again. The executor already dropped
+ * its context, but this will clean up anything that glommed onto the
+ * portal's heap via PortalContext.
+ */
+ MemoryContextDeleteChildren(PortalGetHeapMemory(portal));
}