Re: assertion failure with unique index + partitioning + join

Tender Wang <tndrwang@gmail.com>

From: Tender Wang <tndrwang@gmail.com>
To: Richard Guo <guofenglinux@gmail.com>
Cc: PostgreSQL Hackers <pgsql-hackers@postgresql.org>, Alexander Kuzmenkov <akuzmenkov@tigerdata.com>
Date: 2026-06-16T09:32:06Z
Lists: pgsql-hackers
Richard Guo <guofenglinux@gmail.com> 于2026年6月16日周二 16:27写道:
>
> On Tue, Jun 16, 2026 at 10:58 AM Tender Wang <tndrwang@gmail.com> wrote:
> > It was distributed to (rel:2, table t), but I think "[phrels]
> > Bitmapset [4 3 2]" is incorrect. After leftjoin is removed, we no
> > longer need rel=4 (outerjoin) and rel=3 (t r).
> > But the qual has already been distributed to the (rel: 2) when
> > deconstruct_jointree (). Then the qual is inherited by its child(table
> > p)
> > It seems that we have no logic to process this distributed
> > restrictinfo in remove_useless_joins().
>
> When removing the left join, remove_rel_from_query() fixes up the
> relid sets of RestrictInfos and EquivalenceMembers, and the canonical
> PlaceHolderVars, but it does not rewrite the PlaceHolderVars embedded
> in clause and EC-member expressions.  This is usually fine, because
> later processing consults those relid sets rather than the embedded
> PHVs.
>
> The trouble is that such an expression can later be translated for an
> appendrel child and have its relids recomputed by pull_varnos().  If
> the embedded PlaceHolderVar's phrels still mentions the removed
> relation, pull_varnos() folds it back in, so the rebuilt clause
> references a no-longer-existent rel.  That produces a parameterized
> path keyed on the removed relation, which trips the assertion.

Yes, I came to the same conclusion.

>
> I think we can fix it by stripping the removed relids from the PHVs in
> surviving rels' baserestrictinfo and in EquivalenceClass member
> expressions.  See attached.

The fix I proposed was somewhat specific to this particular issue,
whereas your patch takes a more general approach.
I took a quick pass over the patch and didn't notice any obvious issues.
I won't have time to review it in detail today, but I'll try to take a
closer look tomorrow morning.

>
> (I went back and forth on instead making pull_varnos() robust to the
> stale phrels, but that turned out fragile: it can't reliably
> distinguish a removed relid from a not-yet-built appendrel child, and
> it broke unrelated partitionwise-join plans.)

Interesting, I hadn't thought of that approach.

-- 
Thanks,
Tender Wang



Commits

  1. Strip removed-relation references from PlaceHolderVars at join removal

  2. Clean up remove_rel_from_query() after self-join elimination commit

  3. Fix incorrect handling of subquery pullup