You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Wrong results: eliminate_cross_join drops an equi-join key that spans two cross-joined relations #26058
An inner join whose ON has an ordinary equi-key plus a second equality whose one side spans two relations of a cross join loses the second equality. The query returns rows that do not satisfy the join condition.
extract_equijoin_predicate turns b.id = CASE k.k WHEN 0 THEN a.x ELSE a.y END into an equi-join key whose left expression references both a and k. eliminate_cross_join then flattens (a CROSS JOIN k) JOIN b into one join graph and rebuilds it as (a JOIN b ON a.t = b.t) CROSS JOIN k. The key that references both a and k is not attached to any join and is not kept as a filter.
Reproduced on 55.1.0 and on main (8248a57). Running the query with each logical optimizer rule removed in turn, it is correct without extract_equijoin_predicate or without eliminate_cross_join, and wrong without any other single rule.
To Reproduce
SELECTk.k, b.idFROM (SELECT1AS t, 17AS x, 18AS y) a
CROSS JOIN (SELECT0AS k UNION ALLSELECT1) k
JOIN (SELECT1AS t, CAST(value ASINT) AS id FROM generate_series(0, 20)) b
ONb.t=a.tANDb.id= CASE k.k WHEN 0 THEN a.x ELSE a.y END
ORDER BYk.k, b.id;
returns 42 rows: every b.id from 0 to 20, once for each k.
The optimized logical plan has no trace of the CASE predicate:
Sort: k.k ASC NULLS LAST, b.id ASC NULLS LAST
Projection: k.k, b.id
Cross Join:
Projection: b.id
Inner Join: a.t = b.t
SubqueryAlias: a
Projection: Int64(1) AS t
EmptyRelation: rows=1
SubqueryAlias: b
Projection: Int64(1) AS t, CAST(generate_series().value AS Int32) AS id
TableScan: generate_series() projection=[value]
SubqueryAlias: k
Union
...
Expected behavior
Two rows, (0, 17) and (1, 18).
Without b.t = a.t in the ON clause the result is correct, as it is when the CASE predicate is written in a WHERE instead of the ON clause.
Additional context
Found through Sail, where a query joining a table on s.tic = rt.tic AND s.id = CASE k.k WHEN 0 THEN rt.sector_id ELSE COALESCE(rt.spawn_sector_id, rt.sector_id) END over a cross join with k returned every row for that tic.
Activity
Link apache/datafusion#26058 from the respawn-fog workaround and NOTES
fix(planner): keep ON keys that span cross-joined relations