{
TransactionState s = CurrentTransactionState;
+ /* Ensure we're not running in a doomed memory context */
+ AtAbort_Memory();
+
/*
* Get out of any transaction or nested transaction
*/
break;
case TBLOCK_ABORT:
case TBLOCK_ABORT_END:
- /* AbortTransaction already done, still need Cleanup */
+
+ /*
+ * AbortTransaction is already done, still need Cleanup.
+ * However, if we failed partway through running ROLLBACK,
+ * there will be an active portal running that command, which
+ * we need to shut down before doing CleanupTransaction.
+ */
+ AtAbort_Portals();
CleanupTransaction();
s->blockState = TBLOCK_DEFAULT;
break;
case TBLOCK_SUBABORT_END:
case TBLOCK_SUBABORT_RESTART:
/* As above, but AbortSubTransaction already done */
+ if (s->curTransactionOwner)
+ {
+ /* As in TBLOCK_ABORT, might have a live portal to zap */
+ AtSubAbort_Portals(s->subTransactionId,
+ s->parent->subTransactionId,
+ s->curTransactionOwner,
+ s->parent->curTransactionOwner);
+ }
CleanupSubTransaction();
s = CurrentTransactionState; /* changed by pop */
break;
/* Should be out of all subxacts now */
Assert(s->parent == NULL);
+
+ /* If we didn't actually have anything to do, revert to TopMemoryContext */
+ AtCleanup_Memory();
}
/*
* 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 caused by
- * reaching AtCleanup_Portals with the cleanup hook still unexecuted.
+ * aborted transaction, this is necessary, or we'd reach AtCleanup_Portals
+ * with the cleanup hook still unexecuted.
*/
if (PointerIsValid(portal->cleanup))
{
* well do that now, since the portal can't be executed any more.
*
* In some cases involving cleanup of an already aborted transaction, this
- * prevents an assertion failure caused by reaching AtCleanup_Portals with
- * the cleanup hook still unexecuted.
+ * is necessary, or we'd reach AtCleanup_Portals with the cleanup hook
+ * still unexecuted.
*/
if (PointerIsValid(portal->cleanup))
{
if (portal->portalPinned)
portal->portalPinned = false;
- /* We had better not be calling any user-defined code here */
- Assert(portal->cleanup == NULL);
+ /*
+ * We had better not call any user-defined code during cleanup, so if
+ * the cleanup hook hasn't been run yet, too bad; we'll just skip it.
+ */
+ if (PointerIsValid(portal->cleanup))
+ {
+ elog(WARNING, "skipping cleanup for portal \"%s\"", portal->name);
+ portal->cleanup = NULL;
+ }
/* Zap it. */
PortalDrop(portal, false);
if (portal->portalPinned)
portal->portalPinned = false;
- /* We had better not be calling any user-defined code here */
- Assert(portal->cleanup == NULL);
+ /*
+ * We had better not call any user-defined code during cleanup, so if
+ * the cleanup hook hasn't been run yet, too bad; we'll just skip it.
+ */
+ if (PointerIsValid(portal->cleanup))
+ {
+ elog(WARNING, "skipping cleanup for portal \"%s\"", portal->name);
+ portal->cleanup = NULL;
+ }
/* Zap it. */
PortalDrop(portal, false);