in datafusion/physical-expr/src/equivalence/properties/mod.rs [367:441]
fn discover_new_orderings(&mut self, expr: &Arc<dyn PhysicalExpr>) -> Result<()> {
let normalized_expr = self.eq_group().normalize_expr(Arc::clone(expr));
let eq_class = self
.eq_group
.iter()
.find_map(|class| {
class
.contains(&normalized_expr)
.then(|| class.clone().into_vec())
})
.unwrap_or_else(|| vec![Arc::clone(&normalized_expr)]);
let mut new_orderings: Vec<LexOrdering> = vec![];
for ordering in self.normalized_oeq_class().iter() {
if !ordering[0].expr.eq(&normalized_expr) {
continue;
}
let leading_ordering_options = ordering[0].options;
for equivalent_expr in &eq_class {
let children = equivalent_expr.children();
if children.is_empty() {
continue;
}
// Check if all children match the next expressions in the ordering
let mut all_children_match = true;
let mut child_properties = vec![];
// Build properties for each child based on the next expressions
for (i, child) in children.iter().enumerate() {
if let Some(next) = ordering.get(i + 1) {
if !child.as_ref().eq(next.expr.as_ref()) {
all_children_match = false;
break;
}
child_properties.push(ExprProperties {
sort_properties: SortProperties::Ordered(next.options),
range: Interval::make_unbounded(
&child.data_type(&self.schema)?,
)?,
preserves_lex_ordering: true,
});
} else {
all_children_match = false;
break;
}
}
if all_children_match {
// Check if the expression is monotonic in all arguments
if let Ok(expr_properties) =
equivalent_expr.get_properties(&child_properties)
{
if expr_properties.preserves_lex_ordering
&& SortProperties::Ordered(leading_ordering_options)
== expr_properties.sort_properties
{
// Assume existing ordering is [c ASC, a ASC, b ASC]
// When equality c = f(a,b) is given, if we know that given ordering `[a ASC, b ASC]`,
// ordering `[f(a,b) ASC]` is valid, then we can deduce that ordering `[a ASC, b ASC]` is also valid.
// Hence, ordering `[a ASC, b ASC]` can be added to the state as a valid ordering.
// (e.g. existing ordering where leading ordering is removed)
new_orderings.push(LexOrdering::new(ordering[1..].to_vec()));
break;
}
}
}
}
}
self.oeq_class.add_new_orderings(new_orderings);
Ok(())
}