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
fix(rel): UNWIND of maps feeding two inline-map node patterns fails in optimize_projections #2084
A read that unwinds a list of maps and uses two of the map's fields as inline node properties in one MATCH fails at planning time. It returns no rows and raises an optimizer error.
Found during #1982. The introducing commit is being bisected, and the result will be added here.
Acceptance criteria
The query above returns the correct rows (and count(*)) on in-memory and durable projects, at 1 and 4 partitions.
The same holds for the two-clause form UNWIND ... AS e MATCH (a:N {id: e.a}) MATCH (b:N {id: e.b}), and for the write form that creates a relationship between a and b.
A regression test for each shape fails before the fix.
Root cause (pinned with a per-rule optimizer observer by another session on 2026-10-14):
The fault is in DataFusion 53/54's extract_leaf_expressions and push_down_leaf_projections rule pair, not in GraphForge's demand code and not #2041. The lowered plan is correct and carries var_1.name, var_2.name and node_id.
The two join keys are get_field(var_0,'a') = var_1.id and get_field(var_0,'b') = var_2.id, where var_0 is the unwound map.
extract_leaf_expressions aliases both get_field calls as __datafusion_extracted_N.
push_down_leaf_projections moves both extraction projections onto the Unwind side.
optimize_projections then fails.
Removing either rule makes optimization succeed.
The read form fails deterministically (16/16).
The count(*) and CREATE forms fail nondeterministically (4–7 of 8–12 runs on the same binary), which points at hash or iteration order inside the pushdown rule.
It already fails at 0f5bf2227 (2026-07-31), the oldest commit that compiles after the crate rename, so it has likely failed since the DataFusion 53 adoption. No GraphForge commit introduced it.
Fix in progress on fix/2084-unwind-inline-map-patterns: project every non-column join key into a named column on its input before the join, so no join key is a field-extraction expression. Both DataFusion rules stay enabled. The tests must hold under the nondeterminism, so each form is repeated or the absence of a get_field join key is asserted.
Activity
DecisionNerd commentedon Oct 14, 2026
Root cause (pinned with a per-rule optimizer observer by another session on 2026-10-14):
The fault is in DataFusion 53/54's
extract_leaf_expressionsandpush_down_leaf_projectionsrule pair, not in GraphForge's demand code and not #2041. The lowered plan is correct and carriesvar_1.name,var_2.nameandnode_id.get_field(var_0,'a') = var_1.idandget_field(var_0,'b') = var_2.id, wherevar_0is the unwound map.extract_leaf_expressionsaliases bothget_fieldcalls as__datafusion_extracted_N.push_down_leaf_projectionsmoves both extraction projections onto the Unwind side.optimize_projectionsthen fails.Removing either rule makes optimization succeed.
count(*)andCREATEforms fail nondeterministically (4–7 of 8–12 runs on the same binary), which points at hash or iteration order inside the pushdown rule.0f5bf2227(2026-07-31), the oldest commit that compiles after the crate rename, so it has likely failed since the DataFusion 53 adoption. No GraphForge commit introduced it.Fix in progress on
fix/2084-unwind-inline-map-patterns: project every non-column join key into a named column on its input before the join, so no join key is a field-extraction expression. Both DataFusion rules stay enabled. The tests must hold under the nondeterminism, so each form is repeated or the absence of aget_fieldjoin key is asserted.test(api): cover two inline-map node patterns keyed off one unwound m…
fix(rel): project expression join keys to named columns before leaf e…
chore(deps): vendor datafusion-optimizer 54.1.0 unchanged (Part of #2084
chore(deps): wire the vendored datafusion-optimizer through [patch.cr…
fix(rel): recompute a join's schema when the optimizer rewrites its i…