Skip to content

Commit 7ff0810

Browse files
committed
#17838 Correctly report nullability of implicit casts in predicates
1 parent 7ad94e1 commit 7ff0810

File tree

1 file changed

+31
-2
lines changed

1 file changed

+31
-2
lines changed

datafusion/expr/src/expr_schema.rs

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -679,12 +679,31 @@ impl ExprSchemable for Expr {
679679
}
680680
}
681681

682+
/// Represents the possible values for SQL's three valued logic.
683+
/// `Option<bool>` is not used for this since `None` is used to represent
684+
/// inconclusive answers already.
682685
enum TriStateBool {
683686
True,
684687
False,
685688
Uncertain,
686689
}
687690

691+
impl TryFrom<&ScalarValue> for TriStateBool {
692+
type Error = DataFusionError;
693+
694+
fn try_from(value: &ScalarValue) -> std::result::Result<Self, Self::Error> {
695+
match value {
696+
ScalarValue::Null => Ok(TriStateBool::Uncertain),
697+
ScalarValue::Boolean(b) => Ok(match b {
698+
None => TriStateBool::Uncertain,
699+
Some(true) => TriStateBool::True,
700+
Some(false) => TriStateBool::False,
701+
}),
702+
_ => Self::try_from(&value.cast_to(&DataType::Boolean)?)
703+
}
704+
}
705+
}
706+
688707
struct WhenThenConstEvaluator<'a> {
689708
then_expr: &'a Expr,
690709
input_schema: &'a dyn ExprSchema,
@@ -696,7 +715,7 @@ impl WhenThenConstEvaluator<'_> {
696715
fn const_eval_predicate(&self, predicate: &Expr) -> Option<TriStateBool> {
697716
match predicate {
698717
// Literal null is equivalent to boolean uncertain
699-
Expr::Literal(ScalarValue::Null, _) => Some(TriStateBool::Uncertain),
718+
Expr::Literal(scalar, _) => TriStateBool::try_from(scalar).ok(),
700719
Expr::IsNotNull(e) => {
701720
if let Ok(false) = e.nullable(self.input_schema) {
702721
// If `e` is not nullable, then `e IS NOT NULL` is always true
@@ -845,7 +864,7 @@ impl WhenThenConstEvaluator<'_> {
845864
}
846865
}
847866

848-
/// Determines if the given expression is null.
867+
/// Determines if the given expression evaluates to null.
849868
///
850869
/// This function returns:
851870
/// - `Some(true)` is `expr` is certainly null
@@ -1201,6 +1220,16 @@ mod tests {
12011220
assert_not_nullable(&e, &nullable_schema);
12021221
assert_not_nullable(&e, &not_nullable_schema);
12031222

1223+
// CASE WHEN 0 THEN x ELSE 0
1224+
let e = when(lit(0), col("x")).otherwise(lit(0))?;
1225+
assert_not_nullable(&e, &nullable_schema);
1226+
assert_not_nullable(&e, &not_nullable_schema);
1227+
1228+
// CASE WHEN 1 THEN x ELSE 0
1229+
let e = when(lit(1), col("x")).otherwise(lit(0))?;
1230+
assert_nullable(&e, &nullable_schema);
1231+
assert_not_nullable(&e, &not_nullable_schema);
1232+
12041233
Ok(())
12051234
}
12061235

0 commit comments

Comments
 (0)