Re: Eliminating SPI / SQL from some RI triggers - take 3

From: Amit Langote <amitlangote09(at)gmail(dot)com>
To: Chao Li <li(dot)evan(dot)chao(at)gmail(dot)com>
Cc: Junwang Zhao <zhjwpku(at)gmail(dot)com>, Haibo Yan <tristan(dot)yim(at)gmail(dot)com>, Pavel Stehule <pavel(dot)stehule(at)gmail(dot)com>, PostgreSQL-development <pgsql-hackers(at)postgresql(dot)org>, Tomas Vondra <tomas(at)vondra(dot)me>
Subject: Re: Eliminating SPI / SQL from some RI triggers - take 3
Date: 2026-04-06 09:45:05
Message-ID: CA+HiwqH39QU7vGVx65JH1e0nzVvQc5eVmuY7=qyj0T_+b-HO3A@mail.gmail.com
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

On Fri, Apr 3, 2026 at 6:39 PM Amit Langote <amitlangote09(at)gmail(dot)com> wrote:
> On Fri, Apr 3, 2026 at 5:58 PM Chao Li <li(dot)evan(dot)chao(at)gmail(dot)com> wrote:
> > > On Apr 3, 2026, at 13:52, Amit Langote <amitlangote09(at)gmail(dot)com> wrote:
> > > On Thu, Apr 2, 2026 at 5:00 PM Chao Li <li(dot)evan(dot)chao(at)gmail(dot)com> wrote:
> > >> I plan to spend time testing and tracing this patch tomorrow. But I don’t want to block your progress, if I find anything, I will report to you.
> > >
> > > Sure, I didn't want to leave committing this to the weekend or the next week.
> >
> > I spent several hours debugging this patch today, and I found a problem where the batch mode doesn't seem to handle deferred RI triggers, although the commit message suggests that it should.
> >
> > I traced this scenario:
> > ```
> > CREATE TABLE pk (a int primary key);
> > CREATE TABLE fk (a int references pk(a) DEFERRABLE INITIALLY DEFERRED);
> > BEGIN;
> > INSERT INTO fk VALUES (1);
> > INSERT INTO pk VALUES (1);
> > COMMIT;
> > ```
> >
> > When COMMIT is executed, it reaches RI_FKey_check(), where AfterTriggerIsActive() checks whether afterTriggers.query_depth >= 0. But in the deferred case, afterTriggers.query_depth is -1.
> >
> > From the code:
> > ```
> > if (ri_fastpath_is_applicable(riinfo))
> > {
> > if (AfterTriggerIsActive())
> > {
> > /* Batched path: buffer and probe in groups */
> > ri_FastPathBatchAdd(riinfo, fk_rel, newslot);
> > }
> > else
> > {
> > /* ALTER TABLE validation: per-row, no cache */
> > ri_FastPathCheck(riinfo, fk_rel, newslot);
> > }
> > return PointerGetDatum(NULL);
> > }
> > ```
> >
> > So this ends up falling back to the per-row path for deferred RI checks at COMMIT, even though the intent here seems to be only to bypass the ALTER TABLE validation case, where batch callbacks would never fire, and MyTriggerDepth is 0. So, maybe we can just check MyTriggerDepth>0 in AfterTriggerIsActive().
> >
> > I tried the attached fix. With it, deferred triggers go through the batch mode, and all existing tests still pass.
>
> I think you might be right. Thanks for the patch. It looks correct
> to me at a glance, but I will need to check it a bit more closely
> before committing.

Thinking about this some more, your fix is on the right track but
needs a bit more work -- MyTriggerDepth > 0 is too broad since it
fires for BEFORE triggers too. I have a revised version using a new
afterTriggerFiringDepth counter that I'll push shortly.

Added an open item for tracking in the meantime:
https://wiki.postgresql.org/wiki/PostgreSQL_19_Open_Items#Open_Issues

--
Thanks, Amit Langote

Attachment Content-Type Size
v2-0001-Fix-deferred-FK-check-batching-introduced-by-comm.patch application/octet-stream 5.3 KB

In response to

Responses

Browse pgsql-hackers by date

  From Date Subject
Next Message Jelte Fennema-Nio 2026-04-06 09:47:02 Re: Environment variable to disable diffs file output
Previous Message vignesh C 2026-04-06 09:40:50 Re: Remove commented-out code in 026_overwrite_contrecord.pl