On 6/22/23 13:46, Tomas Vondra wrote:
> ...
>
> I haven't tried the reproducer, but I think I see the issue - we store
> the bitmap as part of the event to be executed later, but the bitmap is
> in per-tuple context and gets reset. So I guess we need to copy it into
> the proper long-lived context (e.g. AfterTriggerEvents).
>
> I'll get that fixed.
>
Alexander, can you try if this fixes the issue for you?
regard
--
Tomas Vondra
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 4b295f8da5..0073f576f0 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -3976,6 +3976,36 @@ afterTriggerCheckState(AfterTriggerShared evtshared)
return ((evtshared->ats_event & AFTER_TRIGGER_INITDEFERRED) != 0);
}
+/* ----------
+ * afterTriggerCopyBitmap()
+ *
+ * Copy bitmap into AfterTriggerEvents memory context.
+ * ----------
+ */
+static Bitmapset *
+afterTriggerCopyBitmap(Bitmapset *src)
+{
+ Bitmapset *dst;
+ MemoryContext oldcxt;
+
+ if (src == NULL)
+ return NULL;
+
+ /* Create event context if we didn't already */
+ if (afterTriggers.event_cxt == NULL)
+ afterTriggers.event_cxt =
+ AllocSetContextCreate(TopTransactionContext,
+ "AfterTriggerEvents",
+ ALLOCSET_DEFAULT_SIZES);
+
+ oldcxt = MemoryContextSwitchTo(afterTriggers.event_cxt);
+
+ dst = bms_copy(src);
+
+ MemoryContextSwitchTo(oldcxt);
+
+ return dst;
+}
/* ----------
* afterTriggerAddEvent()
@@ -6387,7 +6417,7 @@ AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo,
new_shared.ats_table = transition_capture->tcs_private;
else
new_shared.ats_table = NULL;
- new_shared.ats_modifiedcols = modifiedCols;
+ new_shared.ats_modifiedcols = afterTriggerCopyBitmap(modifiedCols);
afterTriggerAddEvent(&afterTriggers.query_stack[afterTriggers.query_depth].events,
&new_event, &new_shared);