Re: assertion failure with unique index + partitioning + join

From: Tender Wang <tndrwang(at)gmail(dot)com>
To: PostgreSQL Hackers <pgsql-hackers(at)postgresql(dot)org>
Cc: Alexander Kuzmenkov <akuzmenkov(at)tigerdata(dot)com>
Subject: Re: assertion failure with unique index + partitioning + join
Date: 2026-06-16 01:58:07
Message-ID: CAHewXNn6ENbO2mYqFd0xwQBFytseyghQkq5Kbe61ijaYR69qsw@mail.gmail.com
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

Alexander Kuzmenkov <akuzmenkov(at)tigerdata(dot)com> 于2026年6月15日周一 23:39写道:
>
> Hi hackers,
>
> While I was running some random testing on the TimescaleDB extension, I noticed that I can easily hit an assertion failure in plain Postgres REL_18_STABLE. I haven't analyzed it at all, but thought I should report this:
>
> CREATE TABLE t (a bool UNIQUE) PARTITION BY LIST (a);
> CREATE TABLE p PARTITION OF t DEFAULT;
> SELECT
> FROM (
> SELECT *
> FROM t
> LEFT JOIN t r USING (a)
> )
> WHERE a
> GROUP BY ();
>
>
> TRAP: failed Assert("bms_is_member(i, root->outer_join_rels)"), File: "../pg/src/backend/optimizer/path/equivclass.c", Line: 3631, PID: 1813021
>

I can reproduce this issue on HEAD.
The root->outer_join_rels is empty, and the i is 3(rel: t r).
The left join can be removed in remove_useless_joins(), in which
root->outer_join_rels is changed to be empty.
But the from->qual in this case has already been distributed to its rel.
(gdb) pgprint brel->baserestrictinfo
RestrictInfo [is_pushed_down=true can_join=false pseudoconstant=false
has_clone=false is_clone=false leakproof=false
has_volatile=VOLATILITY_UNKNOWN security_level=0
num_base_rels=1 rinfo_serial=1 eval_cost={startup = -1,
per_tuple = 0} norm_selec=-1 outer_selec=-1 outer_is_left=false
hashjoinoperator=0 left_bucketsize=-1
right_bucketsize=-1 left_mcvfreq=-1 right_mcvfreq=-1
left_hasheqoperator=0 right_hasheqoperator=0]
[clause]
PlaceHolderVar [phid=1 phlevelsup=0]
[phexpr] Var [varno=2 varattno=1 vartype=16
varreturningtype=VAR_RETURNING_DEFAULT varnosyn=2 varattnosyn=1]
[phrels] Bitmapset [4 3 2]
[clause_relids] Bitmapset [2]
[required_relids] Bitmapset [2]

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().

I need to dig deeper to find out how to fix it.

--
Thanks,
Tender Wang

In response to

Responses

Browse pgsql-hackers by date

  From Date Subject
Next Message Ewan Young 2026-06-16 02:02:15 Re: REPACK CONCURRENTLY fails on tables with generated columns
Previous Message Peter Travers 2026-06-16 01:49:03 Re: [PATCH] proposal to surface index used by replica identity