Skip to content

Commit 40ae37e

Browse files
committed
Narrow injective arithmetic to addition and subtraction only
1 parent eeb3b50 commit 40ae37e

File tree

2 files changed

+12
-12
lines changed

2 files changed

+12
-12
lines changed

datafusion/physical-expr/src/expression_analyzer/default.rs

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -210,20 +210,12 @@ impl ExpressionAnalyzer for DefaultExpressionAnalyzer {
210210
return AnalysisResult::Computed(1);
211211
}
212212

213-
// BinaryExpr: for arithmetic with a literal operand, treat as injective
214-
// (preserves NDV). This is an approximation: col * 0 or col % 1 are
215-
// technically not injective, but the common case (col + 1, col * 2, etc.) is
213+
// BinaryExpr: addition/subtraction with a literal is always injective
214+
// TODO: support more injective operators (e.g. multiply by non-zero)
216215
if let Some(binary) = expr.as_any().downcast_ref::<BinaryExpr>() {
217-
let is_arithmetic = matches!(
218-
binary.op(),
219-
Operator::Plus
220-
| Operator::Minus
221-
| Operator::Multiply
222-
| Operator::Divide
223-
| Operator::Modulo
224-
);
216+
let is_injective = matches!(binary.op(), Operator::Plus | Operator::Minus);
225217

226-
if is_arithmetic {
218+
if is_injective {
227219
// If one side is a literal, the operation is injective on the other side
228220
let left_is_literal = binary.left().as_any().is::<Literal>();
229221
let right_is_literal = binary.right().as_any().is::<Literal>();

datafusion/physical-expr/src/expression_analyzer/tests.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,14 @@ fn test_arithmetic_ndv() {
7373
)) as Arc<dyn PhysicalExpr>;
7474
assert_eq!(registry.get_distinct_count(&plus, &stats), Some(100));
7575

76+
// col - 1: injective, preserves NDV
77+
let minus = Arc::new(BinaryExpr::new(
78+
Arc::clone(&col),
79+
Operator::Minus,
80+
Arc::clone(&lit),
81+
)) as Arc<dyn PhysicalExpr>;
82+
assert_eq!(registry.get_distinct_count(&minus, &stats), Some(100));
83+
7684
// 1 + col: also injective (literal on left)
7785
let plus_rev =
7886
Arc::new(BinaryExpr::new(lit, Operator::Plus, col)) as Arc<dyn PhysicalExpr>;

0 commit comments

Comments
 (0)