in datafusion/optimizer/src/simplify_expressions/guarantees.rs [63:199]
fn f_up(&mut self, expr: Expr) -> Result<Transformed<Expr>> {
if self.guarantees.is_empty() {
return Ok(Transformed::no(expr));
}
match &expr {
Expr::IsNull(inner) => match self.guarantees.get(inner.as_ref()) {
Some(NullableInterval::Null { .. }) => Ok(Transformed::yes(lit(true))),
Some(NullableInterval::NotNull { .. }) => {
Ok(Transformed::yes(lit(false)))
}
_ => Ok(Transformed::no(expr)),
},
Expr::IsNotNull(inner) => match self.guarantees.get(inner.as_ref()) {
Some(NullableInterval::Null { .. }) => Ok(Transformed::yes(lit(false))),
Some(NullableInterval::NotNull { .. }) => Ok(Transformed::yes(lit(true))),
_ => Ok(Transformed::no(expr)),
},
Expr::Between(Between {
expr: inner,
negated,
low,
high,
}) => {
if let (Some(interval), Expr::Literal(low), Expr::Literal(high)) = (
self.guarantees.get(inner.as_ref()),
low.as_ref(),
high.as_ref(),
) {
let expr_interval = NullableInterval::NotNull {
values: Interval::try_new(low.clone(), high.clone())?,
};
let contains = expr_interval.contains(*interval)?;
if contains.is_certainly_true() {
Ok(Transformed::yes(lit(!negated)))
} else if contains.is_certainly_false() {
Ok(Transformed::yes(lit(*negated)))
} else {
Ok(Transformed::no(expr))
}
} else {
Ok(Transformed::no(expr))
}
}
Expr::BinaryExpr(BinaryExpr { left, op, right }) => {
// The left or right side of expression might either have a guarantee
// or be a literal. Either way, we can resolve them to a NullableInterval.
let left_interval = self
.guarantees
.get(left.as_ref())
.map(|interval| Cow::Borrowed(*interval))
.or_else(|| {
if let Expr::Literal(value) = left.as_ref() {
Some(Cow::Owned(value.clone().into()))
} else {
None
}
});
let right_interval = self
.guarantees
.get(right.as_ref())
.map(|interval| Cow::Borrowed(*interval))
.or_else(|| {
if let Expr::Literal(value) = right.as_ref() {
Some(Cow::Owned(value.clone().into()))
} else {
None
}
});
match (left_interval, right_interval) {
(Some(left_interval), Some(right_interval)) => {
let result =
left_interval.apply_operator(op, right_interval.as_ref())?;
if result.is_certainly_true() {
Ok(Transformed::yes(lit(true)))
} else if result.is_certainly_false() {
Ok(Transformed::yes(lit(false)))
} else {
Ok(Transformed::no(expr))
}
}
_ => Ok(Transformed::no(expr)),
}
}
// Columns (if interval is collapsed to a single value)
Expr::Column(_) => {
if let Some(interval) = self.guarantees.get(&expr) {
Ok(Transformed::yes(interval.single_value().map_or(expr, lit)))
} else {
Ok(Transformed::no(expr))
}
}
Expr::InList(InList {
expr: inner,
list,
negated,
}) => {
if let Some(interval) = self.guarantees.get(inner.as_ref()) {
// Can remove items from the list that don't match the guarantee
let new_list: Vec<Expr> = list
.iter()
.filter_map(|expr| {
if let Expr::Literal(item) = expr {
match interval
.contains(NullableInterval::from(item.clone()))
{
// If we know for certain the value isn't in the column's interval,
// we can skip checking it.
Ok(interval) if interval.is_certainly_false() => None,
Ok(_) => Some(Ok(expr.clone())),
Err(e) => Some(Err(e)),
}
} else {
Some(Ok(expr.clone()))
}
})
.collect::<Result<_, DataFusionError>>()?;
Ok(Transformed::yes(Expr::InList(InList {
expr: inner.clone(),
list: new_list,
negated: *negated,
})))
} else {
Ok(Transformed::no(expr))
}
}
_ => Ok(Transformed::no(expr)),
}
}