Skip to content

Commit 7981c34

Browse files
committed
Force READY portals into FAILED state when a transaction or subtransaction
is aborted, if they were created within the failed xact. This prevents ExecutorEnd from being run on them, which is a good idea because they may contain references to tables or other objects that no longer exist. In particular this is hazardous when auto_explain is active, but it's really rather surprising that nobody has seen an issue with this before. I'm back-patching this to 8.4, since that's the first version that contains auto_explain or an ExecutorEnd hook, but I wonder whether we shouldn't back-patch further.
1 parent c0d5be5 commit 7981c34

File tree

1 file changed

+38
-48
lines changed

1 file changed

+38
-48
lines changed

src/backend/utils/mmgr/portalmem.c

Lines changed: 38 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
* Portions Copyright (c) 1994, Regents of the University of California
1313
*
1414
* IDENTIFICATION
15-
* $PostgreSQL: pgsql/src/backend/utils/mmgr/portalmem.c,v 1.116 2010/01/18 02:30:25 tgl Exp $
15+
* $PostgreSQL: pgsql/src/backend/utils/mmgr/portalmem.c,v 1.117 2010/02/18 03:06:46 tgl Exp $
1616
*
1717
*-------------------------------------------------------------------------
1818
*/
@@ -668,6 +668,7 @@ AtAbort_Portals(void)
668668
{
669669
Portal portal = hentry->portal;
670670

671+
/* Any portal that was actually running has to be considered broken */
671672
if (portal->status == PORTAL_ACTIVE)
672673
portal->status = PORTAL_FAILED;
673674

@@ -677,6 +678,15 @@ AtAbort_Portals(void)
677678
if (portal->createSubid == InvalidSubTransactionId)
678679
continue;
679680

681+
/*
682+
* If it was created in the current transaction, we can't do normal
683+
* shutdown on a READY portal either; it might refer to objects
684+
* created in the failed transaction. See comments in
685+
* AtSubAbort_Portals.
686+
*/
687+
if (portal->status == PORTAL_READY)
688+
portal->status = PORTAL_FAILED;
689+
680690
/* let portalcmds.c clean up the state it knows about */
681691
if (PointerIsValid(portal->cleanup))
682692
{
@@ -789,61 +799,41 @@ AtSubAbort_Portals(SubTransactionId mySubid,
789799
continue;
790800

791801
/*
792-
* Force any active portals of my own transaction into FAILED state.
793-
* This is mostly to ensure that a portal running a FETCH will go
794-
* FAILED if the underlying cursor fails. (Note we do NOT want to do
795-
* this to upper-level portals, since they may be able to continue.)
796-
*
797-
* This is only needed to dodge the sanity check in PortalDrop.
802+
* Force any live portals of my own subtransaction into FAILED state.
803+
* We have to do this because they might refer to objects created or
804+
* changed in the failed subtransaction, leading to crashes if
805+
* execution is resumed, or even if we just try to run ExecutorEnd.
806+
* (Note we do NOT do this to upper-level portals, since they cannot
807+
* have such references and hence may be able to continue.)
798808
*/
799-
if (portal->status == PORTAL_ACTIVE)
809+
if (portal->status == PORTAL_READY ||
810+
portal->status == PORTAL_ACTIVE)
800811
portal->status = PORTAL_FAILED;
801812

802-
/*
803-
* If the portal is READY then allow it to survive into the parent
804-
* transaction; otherwise shut it down.
805-
*
806-
* Currently, we can't actually support that because the portal's
807-
* query might refer to objects created or changed in the failed
808-
* subtransaction, leading to crashes if execution is resumed. So,
809-
* even READY portals are deleted. It would be nice to detect whether
810-
* the query actually depends on any such object, instead.
811-
*/
812-
#ifdef NOT_USED
813-
if (portal->status == PORTAL_READY)
813+
/* let portalcmds.c clean up the state it knows about */
814+
if (PointerIsValid(portal->cleanup))
814815
{
815-
portal->createSubid = parentSubid;
816-
if (portal->resowner)
817-
ResourceOwnerNewParent(portal->resowner, parentXactOwner);
816+
(*portal->cleanup) (portal);
817+
portal->cleanup = NULL;
818818
}
819-
else
820-
#endif
821-
{
822-
/* let portalcmds.c clean up the state it knows about */
823-
if (PointerIsValid(portal->cleanup))
824-
{
825-
(*portal->cleanup) (portal);
826-
portal->cleanup = NULL;
827-
}
828819

829-
/* drop cached plan reference, if any */
830-
PortalReleaseCachedPlan(portal);
820+
/* drop cached plan reference, if any */
821+
PortalReleaseCachedPlan(portal);
831822

832-
/*
833-
* Any resources belonging to the portal will be released in the
834-
* upcoming transaction-wide cleanup; they will be gone before we
835-
* run PortalDrop.
836-
*/
837-
portal->resowner = NULL;
823+
/*
824+
* Any resources belonging to the portal will be released in the
825+
* upcoming transaction-wide cleanup; they will be gone before we
826+
* run PortalDrop.
827+
*/
828+
portal->resowner = NULL;
838829

839-
/*
840-
* Although we can't delete the portal data structure proper, we
841-
* can release any memory in subsidiary contexts, such as executor
842-
* state. The cleanup hook was the last thing that might have
843-
* needed data there.
844-
*/
845-
MemoryContextDeleteChildren(PortalGetHeapMemory(portal));
846-
}
830+
/*
831+
* Although we can't delete the portal data structure proper, we
832+
* can release any memory in subsidiary contexts, such as executor
833+
* state. The cleanup hook was the last thing that might have
834+
* needed data there.
835+
*/
836+
MemoryContextDeleteChildren(PortalGetHeapMemory(portal));
847837
}
848838
}
849839

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy