Alexander Kuzmenkov <[email protected]> 于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


Reply via email to