From 09e5658dbdc101db950a139d3d955d0f93c93bde Mon Sep 17 00:00:00 2001 From: Pepijn Van Eeckhoudt Date: Mon, 2 Feb 2026 10:52:21 +0100 Subject: [PATCH 1/2] Adjust case_when DivideByZeroProtection so that "percentage of zeroes" corresponds to "number of times protection is needed" --- datafusion/physical-expr/benches/case_when.rs | 31 +------------------ 1 file changed, 1 insertion(+), 30 deletions(-) diff --git a/datafusion/physical-expr/benches/case_when.rs b/datafusion/physical-expr/benches/case_when.rs index d9b1b565721c..33931a2ba98e 100644 --- a/datafusion/physical-expr/benches/case_when.rs +++ b/datafusion/physical-expr/benches/case_when.rs @@ -564,7 +564,6 @@ fn benchmark_divide_by_zero_protection(c: &mut Criterion, batch_size: usize) { let numerator_col = col("numerator", &batch.schema()).unwrap(); let divisor_col = col("divisor", &batch.schema()).unwrap(); - let divisor_copy_col = col("divisor_copy", &batch.schema()).unwrap(); // DivideByZeroProtection: WHEN condition checks `divisor_col > 0` and division // uses `divisor_col` as divisor. Since the checked column matches the divisor, @@ -578,35 +577,7 @@ fn benchmark_divide_by_zero_protection(c: &mut Criterion, batch_size: usize) { |b| { let when = Arc::new(BinaryExpr::new( Arc::clone(&divisor_col), - Operator::Gt, - lit(0i32), - )); - let then = Arc::new(BinaryExpr::new( - Arc::clone(&numerator_col), - Operator::Divide, - Arc::clone(&divisor_col), - )); - let else_null: Arc = lit(ScalarValue::Int32(None)); - let expr = - Arc::new(case(None, vec![(when, then)], Some(else_null)).unwrap()); - - b.iter(|| black_box(expr.evaluate(black_box(&batch)).unwrap())) - }, - ); - - // ExpressionOrExpression: WHEN condition checks `divisor_copy_col > 0` but - // division uses `divisor_col` as divisor. Since the checked column does NOT - // match the divisor, this falls back to ExpressionOrExpression evaluation. - group.bench_function( - format!( - "{} rows, {}% zeros: ExpressionOrExpression", - batch_size, - (zero_percentage * 100.0) as i32 - ), - |b| { - let when = Arc::new(BinaryExpr::new( - Arc::clone(&divisor_copy_col), - Operator::Gt, + Operator::NotEq, lit(0i32), )); let then = Arc::new(BinaryExpr::new( From 1ed9d7acf19ed4082e87021c385aabe56fac45cc Mon Sep 17 00:00:00 2001 From: Pepijn Van Eeckhoudt Date: Mon, 2 Feb 2026 10:57:41 +0100 Subject: [PATCH 2/2] Add SLTs covering divide-by-zero protection --- datafusion/sqllogictest/test_files/case.slt | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/datafusion/sqllogictest/test_files/case.slt b/datafusion/sqllogictest/test_files/case.slt index 8e0ee08d994a..8bb17b57f634 100644 --- a/datafusion/sqllogictest/test_files/case.slt +++ b/datafusion/sqllogictest/test_files/case.slt @@ -621,6 +621,27 @@ a b c +query I +SELECT CASE WHEN d != 0 THEN n / d ELSE NULL END FROM (VALUES (1, 1), (1, 0), (1, -1)) t(n,d) +---- +1 +NULL +-1 + +query I +SELECT CASE WHEN d > 0 THEN n / d ELSE NULL END FROM (VALUES (1, 1), (1, 0), (1, -1)) t(n,d) +---- +1 +NULL +NULL + +query I +SELECT CASE WHEN d < 0 THEN n / d ELSE NULL END FROM (VALUES (1, 1), (1, 0), (1, -1)) t(n,d) +---- +NULL +NULL +-1 + # EvalMethod::WithExpression using subset of all selected columns in case expression query III SELECT CASE a1 WHEN 1 THEN a1 WHEN 2 THEN a2 WHEN 3 THEN b END, b, c