Re: Segfault in RI UPDATE CASCADE on partitioned tables with LIKE+ATTACH child (attnum drift) - Mailing list pgsql-bugs

From Amit Langote
Subject Re: Segfault in RI UPDATE CASCADE on partitioned tables with LIKE+ATTACH child (attnum drift)
Date
Msg-id CA+HiwqFq=eUX8CJvnw+sqvhiHL1xnP6F8LutAc=GZGK65JQ++A@mail.gmail.com
Whole thread Raw
In response to Re: Segfault in RI UPDATE CASCADE on partitioned tables with LIKE+ATTACH child (attnum drift)  (David Rowley <dgrowleyml@gmail.com>)
Responses Re: Segfault in RI UPDATE CASCADE on partitioned tables with LIKE+ATTACH child (attnum drift)
List pgsql-bugs
On Wed, Oct 22, 2025 at 5:29 AM David Rowley <dgrowleyml@gmail.com> wrote:
> On Wed, 22 Oct 2025 at 02:49, Amit Langote <amitlangote09@gmail.com> wrote:
> > Besides test suite being entirely different in my v5, the only change
> > from your v4 was rewording and moving the new comment in
> > ExecGetTriggerResultRel() into its header comment:
> >
> > @@ -1337,6 +1337,12 @@ InitResultRelInfo(ResultRelInfo *resultRelInfo,
> >   * also provides a way for EXPLAIN ANALYZE to report the runtimes of such
> >   * triggers.)  So we make additional ResultRelInfo's as needed, and save them
> >   * in es_trig_target_relations.
> > + *
> > + * When reusing cached entries from any of these lists, require an exact
> > + * match of ri_RootResultRelInfo and the rootRelInfo passed by the caller.
> > + * This avoids returning an entry created for a different parent context
> > + * and ensures child->parent translation is neither skipped nor applied
> > + * incorrectly.  If no exact match exists, build a new ResultRelInfo.
> >   */
> >  ResultRelInfo *
> >  ExecGetTriggerResultRel(EState *estate, Oid relid,
> > @@ -1347,14 +1353,6 @@ ExecGetTriggerResultRel(EState *estate, Oid relid,
> >      Relation    rel;
> >      MemoryContext oldcontext;
> >
> > -    /*
> > -     * Before creating a new ResultRelInfo, check if we've already made and
> > -     * cached one for this relation.  We must ensure that the given
> > -     * 'rootRelInfo' matches the one stored in the cached ResultRelInfo as
> > -     * trigger handling for partitions can result in mixed requirements for
> > -     * what ri_RootResultRelInfo is set to.
> > -     */
> > -
> >
> > Please take it if you think that's a good change.  That said, I don't
> > have any issue with your v6, code or tests.
>
> The reason I like the comment being within the function body is that I
> didn't see any need to tell the caller to care about this. As far as
> the caller should be concerned, the function should return a correctly
> set up ResultRelInfo. The inner details of how the caching works feels
> like it should be implementation details, and therefore comments about
> that feel better placed inside the function body.

Makes sense.

> > > I also checked to see if there were any changes around what's shown in
> > > the Triggers portion of EXPLAIN ANALYZE for Dmitry's query. Both
> > > patched and unpatched EXPLAIN ANALYZE are the same. I'm not yet clear
> > > on if it's possible something could be different there now for some
> > > other cases that cause additional ResultRelInfos to be added to the
> > > lists.
> >
> > Good point.
> >
> > I made report_triggers() print which list each ResultRelInfo came from
> > (with the attached). It looks like the entries that could have been
> > affected are always in es_trig_target_relations anyway, so the change
> > in ExecGetTriggerResultRel() doesn’t alter what EXPLAIN shows under
> > “Triggers.” I was still a bit surprised, since I expected there might
> > now be an extra entry after we stopped reusing a child entry with a
> > mismatching ri_RootResultRelInfo.
> >
> > I do see child relations listed under “Triggers,” but only when they
> > have trigger events of their own, not when they’re processed as child
> > relations of a root after a CP_UPDATE event. In those cases,
> > afterTriggerInvokeEvents() only passes the instrumentation for the
> > root rel to AfterTriggerExecute(), so the child entries don’t have
> > their ri_TrigInstrument updated and don’t appear in the EXPLAIN
> > output.
>
> That's good to know, so sounds like we're safe from listing any
> additional ResultRelInfos there.

I think so.

> I'm happy to go with v6.

It looks good to me as well.

I also thought about whether the test case could be simplified further
but didn’t come up with anything that still reproduces the failure
cleanly.

I then tried to understand why we end up with an INSERT event on
stages_50_like (queued due to the FK from stages into pipelines)
during the cascaded update on its parent, which creates the rootless
ResultRelInfo in es_trig_target_relations. That same entry was later
reused for the parent’s CP_UPDATE event (queued due to the FK from
builds into stages), leading to the crash. I was curious why we queue
that INSERT event instead of a CP_UPDATE on the parent, since the
latter would have avoided the problem. When I hacked the code to do
that, the crash disappeared -- but that’s not a valid fix, since
FK-side triggers can’t be used with partitioned tables; they assume
heap relations, so queuing CP_UPDATE events for FK-side triggers
doesn’t work in general.

Anyway, just thought to share that here for the record, since it
helped me understand how that rootless ResultRelInfo ends up being
created in the first place.

--
Thanks, Amit Langote



pgsql-bugs by date:

Previous
From: PG Bug reporting form
Date:
Subject: BUG #19093: Behavioral change in walreceiver termination between PostgreSQL 14.17 and 14.18
Next
From: Jacob Champion
Date:
Subject: Re: BUG #19092: scram_free() will free on address which was not malloc()-ed in pg_scram_mech