Skip to content

Commit c54c4e5

Browse files
peter-tothccciudatu
authored andcommitted
Introduce Expr::is_volatile(), adjust TreeNode::exists() (apache#10191)
1 parent 381dbe0 commit c54c4e5

File tree

5 files changed

+16
-37
lines changed

5 files changed

+16
-37
lines changed

datafusion/common/src/tree_node.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -405,18 +405,17 @@ pub trait TreeNode: Sized {
405405
/// Returns true if `f` returns true for any node in the tree.
406406
///
407407
/// Stops recursion as soon as a matching node is found
408-
fn exists<F: FnMut(&Self) -> bool>(&self, mut f: F) -> bool {
408+
fn exists<F: FnMut(&Self) -> Result<bool>>(&self, mut f: F) -> Result<bool> {
409409
let mut found = false;
410410
self.apply(|n| {
411-
Ok(if f(n) {
411+
Ok(if f(n)? {
412412
found = true;
413413
TreeNodeRecursion::Stop
414414
} else {
415415
TreeNodeRecursion::Continue
416416
})
417417
})
418-
.unwrap();
419-
found
418+
.map(|_| found)
420419
}
421420

422421
/// Low-level API used to implement other APIs.

datafusion/expr/src/expr.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1271,7 +1271,16 @@ impl Expr {
12711271

12721272
/// Return true when the expression contains out reference(correlated) expressions.
12731273
pub fn contains_outer(&self) -> bool {
1274-
self.exists(|expr| matches!(expr, Expr::OuterReferenceColumn { .. }))
1274+
self.exists(|expr| Ok(matches!(expr, Expr::OuterReferenceColumn { .. })))
1275+
.unwrap()
1276+
}
1277+
1278+
/// Returns true if the expression is volatile, i.e. whether it can return different
1279+
/// results when evaluated multiple times with the same input.
1280+
pub fn is_volatile(&self) -> Result<bool> {
1281+
self.exists(|expr| {
1282+
Ok(matches!(expr, Expr::ScalarFunction(func) if func.func_def.is_volatile()?))
1283+
})
12751284
}
12761285

12771286
/// Recursively find all [`Expr::Placeholder`] expressions, and
@@ -1931,15 +1940,6 @@ fn create_names(exprs: &[Expr]) -> Result<String> {
19311940
.join(", "))
19321941
}
19331942

1934-
/// Whether the given expression is volatile, i.e. whether it can return different results
1935-
/// when evaluated multiple times with the same input.
1936-
pub fn is_volatile(expr: &Expr) -> Result<bool> {
1937-
match expr {
1938-
Expr::ScalarFunction(func) => func.func_def.is_volatile(),
1939-
_ => Ok(false),
1940-
}
1941-
}
1942-
19431943
#[cfg(test)]
19441944
mod test {
19451945
use crate::expr::Cast;

datafusion/optimizer/src/common_subexpr_eliminate.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ use std::collections::hash_map::Entry;
2121
use std::collections::{BTreeSet, HashMap};
2222
use std::sync::Arc;
2323

24-
use crate::utils::is_volatile_expression;
2524
use crate::{utils, OptimizerConfig, OptimizerRule};
2625

2726
use arrow::datatypes::{DataType, Field};
@@ -661,7 +660,7 @@ impl TreeNodeVisitor for ExprIdentifierVisitor<'_> {
661660
fn f_down(&mut self, expr: &Expr) -> Result<TreeNodeRecursion> {
662661
// related to https://github.com/apache/datafusion/issues/8814
663662
// If the expr contain volatile expression or is a short-circuit expression, skip it.
664-
if expr.short_circuits() || is_volatile_expression(expr)? {
663+
if expr.short_circuits() || expr.is_volatile()? {
665664
self.visit_stack
666665
.push(VisitRecord::JumpMark(self.node_count));
667666
return Ok(TreeNodeRecursion::Jump); // go to f_up
@@ -717,7 +716,7 @@ impl TreeNodeRewriter for CommonSubexprRewriter<'_> {
717716
// The `CommonSubexprRewriter` relies on `ExprIdentifierVisitor` to generate
718717
// the `id_array`, which records the expr's identifier used to rewrite expr. So if we
719718
// skip an expr in `ExprIdentifierVisitor`, we should skip it here, too.
720-
if expr.short_circuits() || is_volatile_expression(&expr)? {
719+
if expr.short_circuits() || expr.is_volatile()? {
721720
return Ok(Transformed::new(expr, false, TreeNodeRecursion::Jump));
722721
}
723722

datafusion/optimizer/src/push_down_filter.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ use std::collections::{HashMap, HashSet};
1818
use std::sync::Arc;
1919

2020
use crate::optimizer::ApplyOrder;
21-
use crate::utils::is_volatile_expression;
2221
use crate::{OptimizerConfig, OptimizerRule};
2322

2423
use datafusion_common::tree_node::{
@@ -705,9 +704,7 @@ impl OptimizerRule for PushDownFilter {
705704

706705
(qualified_name(qualifier, field.name()), expr)
707706
})
708-
.partition(|(_, value)| {
709-
is_volatile_expression(value).unwrap_or(true)
710-
});
707+
.partition(|(_, value)| value.is_volatile().unwrap_or(true));
711708

712709
let mut push_predicates = vec![];
713710
let mut keep_predicates = vec![];

datafusion/optimizer/src/utils.rs

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,7 @@ use std::collections::{BTreeSet, HashMap};
2121

2222
use crate::{OptimizerConfig, OptimizerRule};
2323

24-
use datafusion_common::tree_node::{TreeNode, TreeNodeRecursion};
2524
use datafusion_common::{Column, DFSchema, DFSchemaRef, Result};
26-
use datafusion_expr::expr::is_volatile;
2725
use datafusion_expr::expr_rewriter::replace_col;
2826
use datafusion_expr::utils as expr_utils;
2927
use datafusion_expr::{logical_plan::LogicalPlan, Expr, Operator};
@@ -97,20 +95,6 @@ pub fn log_plan(description: &str, plan: &LogicalPlan) {
9795
trace!("{description}::\n{}\n", plan.display_indent_schema());
9896
}
9997

100-
/// check whether the expression is volatile predicates
101-
pub(crate) fn is_volatile_expression(e: &Expr) -> Result<bool> {
102-
let mut is_volatile_expr = false;
103-
e.apply(|expr| {
104-
Ok(if is_volatile(expr)? {
105-
is_volatile_expr = true;
106-
TreeNodeRecursion::Stop
107-
} else {
108-
TreeNodeRecursion::Continue
109-
})
110-
})?;
111-
Ok(is_volatile_expr)
112-
}
113-
11498
/// Splits a conjunctive [`Expr`] such as `A AND B AND C` => `[A, B, C]`
11599
///
116100
/// See [`split_conjunction_owned`] for more details and an example.

0 commit comments

Comments
 (0)