summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTom Lane2011-03-03 18:03:34 +0000
committerTom Lane2011-03-03 18:04:06 +0000
commit6252c4f9e201f619e5eebda12fa867acd4e4200e (patch)
tree7f6eaa38d85846e4e38593f2d2a7682807143e0a /src
parent32fce70564999a90d48a27c4279a8908e90f3ece (diff)
Run a portal's cleanup hook immediately when pushing it to DONE state.
This works around the problem noted by Yamamoto Takashi in bug #5906, that there were code paths whereby we could reach AtCleanup_Portals with a portal's cleanup hook still unexecuted. The changes I made a few days ago were intended to prevent that from happening, and I think that on balance it's still a good thing to avoid, so I don't want to remove the Assert in AtCleanup_Portals. Hence do this instead.
Diffstat (limited to 'src')
-rw-r--r--src/backend/tcop/pquery.c2
-rw-r--r--src/backend/utils/mmgr/portalmem.c26
-rw-r--r--src/include/utils/portal.h1
3 files changed, 28 insertions, 1 deletions
diff --git a/src/backend/tcop/pquery.c b/src/backend/tcop/pquery.c
index edde5642ee7..1286edee729 100644
--- a/src/backend/tcop/pquery.c
+++ b/src/backend/tcop/pquery.c
@@ -814,7 +814,7 @@ PortalRun(Portal portal, long count, bool isTopLevel,
dest, altdest, completionTag);
/* Prevent portal's commands from being re-executed */
- portal->status = PORTAL_DONE;
+ MarkPortalDone(portal);
/* Always complete at end of RunMulti */
result = true;
diff --git a/src/backend/utils/mmgr/portalmem.c b/src/backend/utils/mmgr/portalmem.c
index 0ca5e110393..7fa66b42212 100644
--- a/src/backend/utils/mmgr/portalmem.c
+++ b/src/backend/utils/mmgr/portalmem.c
@@ -402,6 +402,32 @@ UnpinPortal(Portal portal)
}
/*
+ * MarkPortalDone
+ * Transition a portal from ACTIVE to DONE state.
+ */
+void
+MarkPortalDone(Portal portal)
+{
+ /* Perform the state transition */
+ Assert(portal->status == PORTAL_ACTIVE);
+ portal->status = PORTAL_DONE;
+
+ /*
+ * Allow portalcmds.c to clean up the state it knows about. We might
+ * as well do that now, since the portal can't be executed any more.
+ *
+ * In some cases involving execution of a ROLLBACK command in an already
+ * aborted transaction, this prevents an assertion failure from reaching
+ * AtCleanup_Portals with the cleanup hook still unexecuted.
+ */
+ if (PointerIsValid(portal->cleanup))
+ {
+ (*portal->cleanup) (portal);
+ portal->cleanup = NULL;
+ }
+}
+
+/*
* PortalDrop
* Destroy the portal.
*/
diff --git a/src/include/utils/portal.h b/src/include/utils/portal.h
index dd88451f951..3068003caa3 100644
--- a/src/include/utils/portal.h
+++ b/src/include/utils/portal.h
@@ -206,6 +206,7 @@ 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 MarkPortalDone(Portal portal);
extern void PortalDrop(Portal portal, bool isTopCommit);
extern Portal GetPortalByName(const char *name);
extern void PortalDefineQuery(Portal portal,