What do you mean by saying "bug"? Do you mean that "c.relkind IS NULL OR c.relkind = 'c'" should be pushed through the first join?
Calcite could do this now in FilterJoinRule[1]. [1] https://github.com/apache/calcite/blob/c945b7f49b99538748c871557f6ac80957be2b6e/core/src/main/java/org/apache/calcite/rel/rules/FilterJoinRule.java#L58 Dmitry Sysolyatin <[email protected]> 于2022年10月28日周五 00:52写道: > Hi! > > I tried to execute query the following query against calcite: > > SELECT t.oid,t.*,c.relkind,format_type(nullif(t.typbasetype, 0), > t.typtypmod) as base_type_name, d.description > FROM pg_catalog.pg_type t > LEFT OUTER JOIN pg_catalog.pg_type et ON et.oid=t.typelem > LEFT OUTER JOIN pg_catalog.pg_class c ON c.oid=t.typrelid > LEFT OUTER JOIN pg_catalog.pg_description d ON t.oid=d.objoid > WHERE t.typname IS NOT NULL > AND (c.relkind IS NULL OR c.relkind = 'c') AND (et.typcategory IS NULL OR > et.typcategory <> 'C') > > For some reason, filtering by c.relkind is applied after joining. > > LogicalProject(oid=[$0], oid0=[$0], typname=[$1], typnamespace=[$2], > typowner=[$3], typlen=[$4], typbyval=[$5], typtype=[$6], typcategory=[$7], > typispreferred=[$8], typisdefined=[$9], typdelim=[$10], typrelid=[$11], > typelem=[$12], typarray=[$13], typinput=[$14], typoutput=[$15], > typreceive=[$16], typsend=[$17], typmodin=[$18], typmodout=[$19], > typanalyze=[$20], typalign=[$21], typstorage=[$22], typnotnull=[$23], > typbasetype=[$24], typtypmod=[$25], typndims=[$26], typcollation=[$27], > typdefaultbin=[$28], typdefault=[$29], typacl=[$30], relkind=[$78], > base_type_name=[format_type(CASE(=($24, 0), null:INTEGER, $24), $25)], > description=[$98]) > LogicalFilter(condition=[AND(IS NOT NULL($1), OR(IS NULL($78), =($78, > _UTF-16LE'c')), OR(IS NULL($38), <>($38, _UTF-16LE'C')))]) > LogicalJoin(condition=[=($0, $95)], joinType=[left]) > LogicalJoin(condition=[=($62, $11)], joinType=[left]) > LogicalJoin(condition=[=($31, $12)], joinType=[left]) > LogicalTableScan(table=[[default, pg_catalog, pg_type]]) > LogicalTableScan(table=[[default, pg_catalog, pg_type]]) > LogicalTableScan(table=[[default, pg_catalog, pg_class]]) > LogicalTableScan(table=[[default, pg_catalog, pg_description]]) > > > > Postgres plan generates the following plan for the same query > Nested Loop Left Join (cost=22.47..44.73 rows=1 width=322) > -> Nested Loop Left Join (cost=22.18..43.94 rows=1 width=261) > Filter: ((et.typcategory IS NULL) OR (et.typcategory <> > 'C'::"char")) > -> Hash Left Join (cost=21.91..43.52 rows=1 width=261) > Hash Cond: (t.typrelid = c.oid) > Filter: (c.relkind IS NULL) > -> Seq Scan on pg_type t (cost=0.00..20.01 rows=601 > width=260) > Filter: (typname IS NOT NULL) > -> Hash (cost=16.96..16.96 rows=396 width=5) > -> Seq Scan on pg_class c (cost=0.00..16.96 rows=396 > width=5) > -> Index Scan using pg_type_oid_index on pg_type et > (cost=0.28..0.41 rows=1 width=5) > Index Cond: (oid = t.typelem) > -> Index Scan using pg_description_o_c_o_index on pg_description d > (cost=0.28..0.77 rows=1 width=29) > Index Cond: (objoid = t.oid) > (14 rows) > > Is it a bug or maybe there is a setting that changes this behaviour ? > -- Best, Benchao Li
