Skip to content

Commit 2f80934

Browse files
feat[vortex-expr]: is_fallible analysis (#5546)
Signed-off-by: Joe Isaacs <[email protected]>
1 parent c631d4c commit 2f80934

File tree

4 files changed

+100
-3
lines changed

4 files changed

+100
-3
lines changed
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
// SPDX-FileCopyrightText: Copyright the Vortex contributors
3+
4+
use crate::expr::Expression;
5+
use crate::expr::analysis::BooleanLabels;
6+
use crate::expr::label_tree;
7+
8+
pub fn label_is_fallible(expr: &Expression) -> BooleanLabels<'_> {
9+
label_tree(expr, |expr| expr.is_fallible(), |acc, &child| acc | child)
10+
}
11+
12+
#[cfg(test)]
13+
mod tests {
14+
use super::*;
15+
use crate::expr::exprs::binary::checked_add;
16+
use crate::expr::exprs::binary::eq;
17+
use crate::expr::exprs::get_item::col;
18+
use crate::expr::exprs::is_null::is_null;
19+
use crate::expr::exprs::literal::lit;
20+
use crate::expr::exprs::merge::DuplicateHandling;
21+
use crate::expr::exprs::merge::merge_opts;
22+
use crate::expr::exprs::not::not;
23+
24+
#[test]
25+
fn not_is_not_fallible() {
26+
let expr = not(col("x"));
27+
let labels = label_is_fallible(&expr);
28+
assert_eq!(labels.get(&expr), Some(&false));
29+
}
30+
31+
#[test]
32+
fn checked_add_defaults_to_fallible() {
33+
let expr = checked_add(col("a"), col("b"));
34+
let labels = label_is_fallible(&expr);
35+
assert_eq!(labels.get(&expr), Some(&true));
36+
}
37+
38+
#[test]
39+
fn eq_not_fallible() {
40+
let expr = eq(col("a"), lit(5));
41+
let labels = label_is_fallible(&expr);
42+
assert_eq!(labels.get(&expr), Some(&false));
43+
}
44+
45+
#[test]
46+
fn merge_with_error_handling_is_fallible() {
47+
let expr = merge_opts([col("a"), col("b")], DuplicateHandling::Error);
48+
let labels = label_is_fallible(&expr);
49+
assert_eq!(labels.get(&expr), Some(&true));
50+
}
51+
52+
#[test]
53+
fn merge_with_rightmost_handling_is_not_fallible() {
54+
let expr = merge_opts([col("a"), col("b")], DuplicateHandling::RightMost);
55+
let labels = label_is_fallible(&expr);
56+
assert_eq!(labels.get(&expr), Some(&false));
57+
}
58+
59+
#[test]
60+
fn nested_with_fallible_child() {
61+
let child = checked_add(col("a"), col("b"));
62+
let expr = not(child.clone());
63+
let labels = label_is_fallible(&expr);
64+
assert_eq!(labels.get(&child), Some(&true));
65+
assert_eq!(labels.get(&expr), Some(&true));
66+
}
67+
68+
#[test]
69+
fn nested_without_fallible_child() {
70+
let child = is_null(col("x"));
71+
let expr = not(child.clone());
72+
let labels = label_is_fallible(&expr);
73+
assert_eq!(labels.get(&child), Some(&false));
74+
assert_eq!(labels.get(&expr), Some(&false));
75+
}
76+
}

vortex-array/src/expr/analysis/mod.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@
22
// SPDX-FileCopyrightText: Copyright the Vortex contributors
33

44
pub mod annotation;
5+
mod fallible;
56
pub mod immediate_access;
67
mod labeling;
78
mod null_sensitive;
89

910
pub use annotation::*;
11+
pub use fallible::label_is_fallible;
1012
pub use immediate_access::*;
1113
pub use labeling::*;
12-
pub use null_sensitive::*;
14+
pub use null_sensitive::BooleanLabels;
15+
pub use null_sensitive::label_null_sensitive;

vortex-array/src/expr/analysis/null_sensitive.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@ use vortex_utils::aliases::hash_map::HashMap;
66
use super::labeling::label_tree;
77
use crate::expr::Expression;
88

9-
pub type NullSensitiveLabels<'a> = HashMap<&'a Expression, bool>;
9+
pub type BooleanLabels<'a> = HashMap<&'a Expression, bool>;
1010

1111
/// Label each expression in the tree with whether it is null-sensitive.
1212
///
1313
/// See [`crate::expr::VTable::is_null_sensitive`] for a definition of null sensitivity.
1414
/// This function operates on a tree of expressions, not just a single expression.
15-
pub fn label_null_sensitive(expr: &Expression) -> NullSensitiveLabels<'_> {
15+
pub fn label_null_sensitive(expr: &Expression) -> BooleanLabels<'_> {
1616
label_tree(
1717
expr,
1818
|expr| expr.is_null_sensitive(),

vortex-array/src/expr/exprs/binary.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,24 @@ impl VTable for Binary {
256256
fn is_null_sensitive(&self, _instance: &Self::Instance) -> bool {
257257
false
258258
}
259+
260+
fn is_fallible(&self, instance: &Self::Instance) -> bool {
261+
// Opt-in not out for fallibility.
262+
// Arithmetic operations could be better modelled here.
263+
let infallible = matches!(
264+
instance,
265+
Operator::Eq
266+
| Operator::NotEq
267+
| Operator::Gt
268+
| Operator::Gte
269+
| Operator::Lt
270+
| Operator::Lte
271+
| Operator::And
272+
| Operator::Or
273+
);
274+
275+
!infallible
276+
}
259277
}
260278

261279
impl ExpressionView<'_, Binary> {

0 commit comments

Comments
 (0)