Skip to content

Commit 4f31f72

Browse files
nameexhaustionritchie46
authored andcommitted
fix: Fix ColumnNotFound due to projection between filter/cache in CSPE (#26946)
1 parent 71873e5 commit 4f31f72

2 files changed

Lines changed: 60 additions & 2 deletions

File tree

crates/polars-plan/src/plans/optimizer/cse/cache_states.rs

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -373,10 +373,42 @@ pub(super) fn set_cache_states(
373373
.block_at_cache(1);
374374
let lp = pred_pd.optimize(start_lp, lp_arena, expr_arena)?;
375375
lp_arena.replace(node, lp.clone());
376+
377+
// TODO: Drop filter column if it isn't used after the filter.
378+
379+
let mut updated_cache_node = node;
380+
381+
loop {
382+
match lp_arena.get(updated_cache_node) {
383+
IR::Cache { .. } => break,
384+
IR::SimpleProjection { input, .. } => updated_cache_node = *input,
385+
_ => unreachable!(),
386+
}
387+
}
388+
376389
for &parents in &v.parents[1..] {
377-
let node = get_filter_node(parents, lp_arena)
390+
let filter_node = get_filter_node(parents, lp_arena)
378391
.expect("expected filter; this is an optimizer bug");
379-
lp_arena.replace(node, lp.clone());
392+
393+
let IR::Filter { input, .. } = lp_arena.get(filter_node) else {
394+
unreachable!()
395+
};
396+
397+
let new_lp = match lp_arena.get(*input) {
398+
IR::SimpleProjection { input, columns } => {
399+
debug_assert!(matches!(lp_arena.get(*input), IR::Cache { .. }));
400+
IR::SimpleProjection {
401+
input: updated_cache_node,
402+
columns: columns.clone(),
403+
}
404+
},
405+
ir => {
406+
debug_assert!(matches!(ir, IR::Cache { .. }));
407+
lp_arena.get(updated_cache_node).clone()
408+
},
409+
};
410+
411+
lp_arena.replace(filter_node, new_lp);
380412
}
381413
} else {
382414
let child = *v.children.first().unwrap();

py-polars/tests/unit/lazyframe/test_cse.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1330,3 +1330,29 @@ def f_b(df: pl.DataFrame) -> pl.DataFrame:
13301330
schema={"A": pl.Int32, "PART": pl.Int32, "B": pl.Int32},
13311331
)
13321332
assert_frame_equal(out, expected)
1333+
1334+
1335+
def test_cspe_projection_between_filter_and_cache_26916() -> None:
1336+
lf = pl.LazyFrame(
1337+
{
1338+
"VendorID": [1, 1, 2, 2, 2],
1339+
"total_amount": [10.0, 20.0, 30.0, 40.0, 50.0],
1340+
"passenger_count": [1, 2, 1, 3, 2],
1341+
}
1342+
)
1343+
1344+
g1 = lf.group_by("VendorID").agg(pl.mean("total_amount"))
1345+
g2 = lf.group_by("VendorID").agg(pl.mean("passenger_count"))
1346+
1347+
q = g1.join(g2, "VendorID").filter(VendorID=1)
1348+
1349+
assert_frame_equal(
1350+
q.collect(),
1351+
pl.DataFrame(
1352+
{
1353+
"VendorID": 1,
1354+
"total_amount": 15.0,
1355+
"passenger_count": 1.5,
1356+
}
1357+
),
1358+
)

0 commit comments

Comments
 (0)