summaryrefslogtreecommitdiff
path: root/src/include/utils/portal.h
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2015-09-04 13:36:50 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2015-09-04 13:36:50 -0400
commit9e9b310d8bcac76bf19f99f3c90e7c08366c52f7 (patch)
tree6c272bdd9a9472b435e0095dde0e591ba2b16520 /src/include/utils/portal.h
parenta7f8e306d2af5b497077a0dc1bfd2cb27aa232f4 (diff)
Fix subtransaction cleanup after an outer-subtransaction portal fails.
Formerly, we treated only portals created in the current subtransaction as having failed during subtransaction abort. However, if the error occurred while running a portal created in an outer subtransaction (ie, a cursor declared before the last savepoint), that has to be considered broken too. To allow reliable detection of which ones those are, add a bookkeeping field to struct Portal that tracks the innermost subtransaction in which each portal has actually been executed. (Without this, we'd end up failing portals containing functions that had called the subtransaction, thereby breaking plpgsql exception blocks completely.) In addition, when we fail an outer-subtransaction Portal, transfer its resources into the subtransaction's resource owner, so that they're released early in cleanup of the subxact. This fixes a problem reported by Jim Nasby in which a function executed in an outer-subtransaction cursor could cause an Assert failure or crash by referencing a relation created within the inner subtransaction. The proximate cause of the Assert failure is that AtEOSubXact_RelationCache assumed it could blow away a relcache entry without first checking that the entry had zero refcount. That was a bad idea on its own terms, so add such a check there, and to the similar coding in AtEOXact_RelationCache. This provides an independent safety measure in case there are still ways to provoke the situation despite the Portal-level changes. This has been broken since subtransactions were invented, so back-patch to all supported branches. Tom Lane and Michael Paquier
Diffstat (limited to 'src/include/utils/portal.h')
-rw-r--r--src/include/utils/portal.h18
1 files changed, 15 insertions, 3 deletions
diff --git a/src/include/utils/portal.h b/src/include/utils/portal.h
index 67343ec6057..1203cc3ffc9 100644
--- a/src/include/utils/portal.h
+++ b/src/include/utils/portal.h
@@ -119,12 +119,15 @@ typedef struct PortalData
MemoryContext heap; /* subsidiary memory for portal */
ResourceOwner resowner; /* resources owned by portal */
void (*cleanup) (Portal portal); /* cleanup hook */
- SubTransactionId createSubid; /* the ID of the creating subxact */
/*
- * if createSubid is InvalidSubTransactionId, the portal is held over from
- * a previous transaction
+ * State data for remembering which subtransaction(s) the portal was
+ * created or used in. If the portal is held over from a previous
+ * transaction, both subxids are InvalidSubTransactionId. Otherwise,
+ * createSubid is the creating subxact and activeSubid is the last subxact
+ * in which we ran the portal.
*/
+ SubTransactionId createSubid; /* the creating subxact */
/* The query or queries the portal will execute */
const char *sourceText; /* text of query (as of 8.4, never NULL) */
@@ -175,6 +178,13 @@ typedef struct PortalData
/* Presentation data, primarily used by the pg_cursors system view */
TimestampTz creation_time; /* time at which this portal was defined */
bool visible; /* include this portal in pg_cursors? */
+
+ /*
+ * This field belongs with createSubid, but in pre-9.5 branches, add it
+ * at the end to avoid creating an ABI break for extensions that examine
+ * Portal structs.
+ */
+ SubTransactionId activeSubid; /* the last subxact with activity */
} PortalData;
/*
@@ -201,12 +211,14 @@ extern void AtSubCommit_Portals(SubTransactionId mySubid,
ResourceOwner parentXactOwner);
extern void AtSubAbort_Portals(SubTransactionId mySubid,
SubTransactionId parentSubid,
+ ResourceOwner myXactOwner,
ResourceOwner parentXactOwner);
extern void AtSubCleanup_Portals(SubTransactionId mySubid);
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 MarkPortalActive(Portal portal);
extern void MarkPortalDone(Portal portal);
extern void MarkPortalFailed(Portal portal);
extern void PortalDrop(Portal portal, bool isTopCommit);