Describe the bug
Physical lambda expressions can fail during execution after an optimizer rewrite moves the expression across a schema boundary.
This affects at least two paths:
- collapsing consecutive
ProjectionExecs;
- pushing a join-filter expression below a
NestedLoopJoinExec.
In both cases, the query plans successfully, but the physical LambdaVariable retains an index and FieldRef that no longer match the RecordBatch against which it is evaluated.
To Reproduce
Reproducer 1: projection-chain collapse
SET datafusion.sql_parser.dialect = spark;
SELECT array_transform(arr, x -> x)
FROM (
SELECT arr
FROM (VALUES ([1, 2], 7)) AS t(arr, padding)
) AS q;
Actual result:
Error: Execution error: Field of physical LambdaVariable with index 0 doesn't match batch field during evaluation Field { "x": nullable Int64 } != Field { "column2": Int64 }
The optimized physical plan has collapsed the intermediate projection:
ProjectionExec
array_transform(column1, (x) -> x@1)
DataSourceExec
Reproducer 2: NestedLoopJoin filter pushdown
SET datafusion.sql_parser.dialect = spark;
SELECT l.id, r.k
FROM (
VALUES
(1, [1], 10, 20),
(2, arrow_cast([NULL], 'List(Int64)'), 30, 40)
) AS l(id, arr, padding_1, padding_2)
JOIN (VALUES (0), (1), (2)) AS r(k)
ON (cardinality(array_filter(l.arr, x -> x IS NOT NULL)) > 0)
= (l.id > r.k)
ORDER BY l.id, r.k;
Actual result:
Error: Execution error: Field of physical LambdaVariable with index 0 doesn't match batch field during evaluation Field { "x": nullable Int64 } != Field { "column4": Int64 }
EXPLAIN confirms that this goes through NestedLoopJoinExec and join-filter projection pushdown:
NestedLoopJoinExec
ProjectionExec
arr: column2
id: column1
join_proj_push_down_1:
cardinality(
array_filter(column2, (x) -> x@3 IS NOT NULL)
) > 0
Expected behavior
The first query should return:
The second query should return:
Additional context
Related lakehq/sail#2413
Describe the bug
Physical lambda expressions can fail during execution after an optimizer rewrite moves the expression across a schema boundary.
This affects at least two paths:
ProjectionExecs;NestedLoopJoinExec.In both cases, the query plans successfully, but the physical
LambdaVariableretains an index andFieldRefthat no longer match theRecordBatchagainst which it is evaluated.To Reproduce
Reproducer 1: projection-chain collapse
Actual result:
The optimized physical plan has collapsed the intermediate projection:
Reproducer 2: NestedLoopJoin filter pushdown
Actual result:
EXPLAINconfirms that this goes throughNestedLoopJoinExecand join-filter projection pushdown:Expected behavior
The first query should return:
The second query should return:
Additional context
Related lakehq/sail#2413