aboutsummaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/access/transam/xact.c1
-rw-r--r--src/backend/tcop/pquery.c27
-rw-r--r--src/backend/utils/mmgr/portalmem.c4
-rw-r--r--src/backend/utils/time/snapmgr.c17
4 files changed, 41 insertions, 8 deletions
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index 6597ec45a95..4cc38f0d85e 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -4863,6 +4863,7 @@ CommitSubTransaction(void)
AfterTriggerEndSubXact(true);
AtSubCommit_Portals(s->subTransactionId,
s->parent->subTransactionId,
+ s->parent->nestingLevel,
s->parent->curTransactionOwner);
AtEOSubXact_LargeObject(true, s->subTransactionId,
s->parent->subTransactionId);
diff --git a/src/backend/tcop/pquery.c b/src/backend/tcop/pquery.c
index 57ffd9bc4c4..61e18926a5b 100644
--- a/src/backend/tcop/pquery.c
+++ b/src/backend/tcop/pquery.c
@@ -480,7 +480,9 @@ PortalStart(Portal portal, ParamListInfo params,
* We could remember the snapshot in portal->portalSnapshot,
* but presently there seems no need to, as this code path
* cannot be used for non-atomic execution. Hence there can't
- * be any commit/abort that might destroy the snapshot.
+ * be any commit/abort that might destroy the snapshot. Since
+ * we don't do that, there's also no need to force a
+ * non-default nesting level for the snapshot.
*/
/*
@@ -1136,9 +1138,15 @@ PortalRunUtility(Portal portal, PlannedStmt *pstmt,
snapshot = RegisterSnapshot(snapshot);
portal->holdSnapshot = snapshot;
}
- /* In any case, make the snapshot active and remember it in portal */
- PushActiveSnapshot(snapshot);
- /* PushActiveSnapshot might have copied the snapshot */
+
+ /*
+ * In any case, make the snapshot active and remember it in portal.
+ * Because the portal now references the snapshot, we must tell
+ * snapmgr.c that the snapshot belongs to the portal's transaction
+ * level, else we risk portalSnapshot becoming a dangling pointer.
+ */
+ PushActiveSnapshotWithLevel(snapshot, portal->createLevel);
+ /* PushActiveSnapshotWithLevel might have copied the snapshot */
portal->portalSnapshot = GetActiveSnapshot();
}
else
@@ -1789,8 +1797,13 @@ EnsurePortalSnapshotExists(void)
elog(ERROR, "cannot execute SQL without an outer snapshot or portal");
Assert(portal->portalSnapshot == NULL);
- /* Create a new snapshot and make it active */
- PushActiveSnapshot(GetTransactionSnapshot());
- /* PushActiveSnapshot might have copied the snapshot */
+ /*
+ * Create a new snapshot, make it active, and remember it in portal.
+ * Because the portal now references the snapshot, we must tell snapmgr.c
+ * that the snapshot belongs to the portal's transaction level, else we
+ * risk portalSnapshot becoming a dangling pointer.
+ */
+ PushActiveSnapshotWithLevel(GetTransactionSnapshot(), portal->createLevel);
+ /* PushActiveSnapshotWithLevel might have copied the snapshot */
portal->portalSnapshot = GetActiveSnapshot();
}
diff --git a/src/backend/utils/mmgr/portalmem.c b/src/backend/utils/mmgr/portalmem.c
index 5c30e141f52..58674d611d4 100644
--- a/src/backend/utils/mmgr/portalmem.c
+++ b/src/backend/utils/mmgr/portalmem.c
@@ -210,6 +210,7 @@ CreatePortal(const char *name, bool allowDup, bool dupSilent)
portal->cleanup = PortalCleanup;
portal->createSubid = GetCurrentSubTransactionId();
portal->activeSubid = portal->createSubid;
+ portal->createLevel = GetCurrentTransactionNestLevel();
portal->strategy = PORTAL_MULTI_QUERY;
portal->cursorOptions = CURSOR_OPT_NO_SCROLL;
portal->atStart = true;
@@ -657,6 +658,7 @@ HoldPortal(Portal portal)
*/
portal->createSubid = InvalidSubTransactionId;
portal->activeSubid = InvalidSubTransactionId;
+ portal->createLevel = 0;
}
/*
@@ -940,6 +942,7 @@ PortalErrorCleanup(void)
void
AtSubCommit_Portals(SubTransactionId mySubid,
SubTransactionId parentSubid,
+ int parentLevel,
ResourceOwner parentXactOwner)
{
HASH_SEQ_STATUS status;
@@ -954,6 +957,7 @@ AtSubCommit_Portals(SubTransactionId mySubid,
if (portal->createSubid == mySubid)
{
portal->createSubid = parentSubid;
+ portal->createLevel = parentLevel;
if (portal->resowner)
ResourceOwnerNewParent(portal->resowner, parentXactOwner);
}
diff --git a/src/backend/utils/time/snapmgr.c b/src/backend/utils/time/snapmgr.c
index 2968c7f7b7d..dca1bc8afca 100644
--- a/src/backend/utils/time/snapmgr.c
+++ b/src/backend/utils/time/snapmgr.c
@@ -679,9 +679,24 @@ FreeSnapshot(Snapshot snapshot)
void
PushActiveSnapshot(Snapshot snap)
{
+ PushActiveSnapshotWithLevel(snap, GetCurrentTransactionNestLevel());
+}
+
+/*
+ * PushActiveSnapshotWithLevel
+ * Set the given snapshot as the current active snapshot
+ *
+ * Same as PushActiveSnapshot except that caller can specify the
+ * transaction nesting level that "owns" the snapshot. This level
+ * must not be deeper than the current top of the snapshot stack.
+ */
+void
+PushActiveSnapshotWithLevel(Snapshot snap, int snap_level)
+{
ActiveSnapshotElt *newactive;
Assert(snap != InvalidSnapshot);
+ Assert(ActiveSnapshot == NULL || snap_level >= ActiveSnapshot->as_level);
newactive = MemoryContextAlloc(TopTransactionContext, sizeof(ActiveSnapshotElt));
@@ -695,7 +710,7 @@ PushActiveSnapshot(Snapshot snap)
newactive->as_snap = snap;
newactive->as_next = ActiveSnapshot;
- newactive->as_level = GetCurrentTransactionNestLevel();
+ newactive->as_level = snap_level;
newactive->as_snap->active_count++;