Describe the bug
InterleaveExec::with_new_children uses assert_or_internal_err!(can_interleave(children.iter())) which panics when children's partitioning diverges after optimizer rewrites. This can happen when multiple physical optimizer passes modify the plan between when InterleaveExec is created and when with_new_children is called.
To Reproduce
This occurs in practice when:
EnforceDistribution creates InterleaveExec for a UnionExec whose children all have matching Hash partitioning
- Subsequent optimizer passes (e.g.
JoinSelection, additional EnforceDistribution/EnforceSorting passes) modify children's plan structure, changing their output partitioning
with_new_children is called on the InterleaveExec with the modified children → assertion panic
We hit this with a complex UNION ALL query (5 subqueries with JOINs, each reading from different table types — partitioned, single-file, MVs). The materialization task panics every time:
join_selection
caused by
Internal error: Assertion failed: can_interleave(children.iter()): Can not create InterleaveExec: new children can not be interleaved.
Expected behavior
InterleaveExec::with_new_children should gracefully fall back to UnionExec when children are no longer interleavable, instead of panicking. The existing comment in the code already acknowledges this possibility:
// New children are no longer interleavable, which might be a bug of optimization rewrite.
Correctness is preserved when falling back to UnionExec — EnforceDistribution will add RepartitionExec as needed. Only the interleave optimization is lost.
Proposed fix
fn with_new_children(
self: Arc<Self>,
children: Vec<Arc<dyn ExecutionPlan>>,
) -> Result<Arc<dyn ExecutionPlan>> {
if can_interleave(children.iter()) {
Ok(Arc::new(InterleaveExec::try_new(children)?))
} else {
UnionExec::try_new(children)
}
}
Will submit a PR with the fix and unit tests.
Describe the bug
InterleaveExec::with_new_childrenusesassert_or_internal_err!(can_interleave(children.iter()))which panics when children's partitioning diverges after optimizer rewrites. This can happen when multiple physical optimizer passes modify the plan between whenInterleaveExecis created and whenwith_new_childrenis called.To Reproduce
This occurs in practice when:
EnforceDistributioncreatesInterleaveExecfor aUnionExecwhose children all have matching Hash partitioningJoinSelection, additionalEnforceDistribution/EnforceSortingpasses) modify children's plan structure, changing their output partitioningwith_new_childrenis called on theInterleaveExecwith the modified children → assertion panicWe hit this with a complex UNION ALL query (5 subqueries with JOINs, each reading from different table types — partitioned, single-file, MVs). The materialization task panics every time:
Expected behavior
InterleaveExec::with_new_childrenshould gracefully fall back toUnionExecwhen children are no longer interleavable, instead of panicking. The existing comment in the code already acknowledges this possibility:// New children are no longer interleavable, which might be a bug of optimization rewrite.Correctness is preserved when falling back to
UnionExec—EnforceDistributionwill addRepartitionExecas needed. Only the interleave optimization is lost.Proposed fix
Will submit a PR with the fix and unit tests.