datafusion_expr/
simplify.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18//! Structs and traits to provide the information needed for expression simplification.
19
20use arrow::datatypes::DataType;
21use datafusion_common::{DFSchemaRef, DataFusionError, Result};
22
23use crate::{execution_props::ExecutionProps, Expr, ExprSchemable};
24
25/// Provides the information necessary to apply algebraic simplification to an
26/// [Expr]. See [SimplifyContext] for one concrete implementation.
27///
28/// This trait exists so that other systems can plug schema
29/// information in without having to create `DFSchema` objects. If you
30/// have a [`DFSchemaRef`] you can use [`SimplifyContext`]
31pub trait SimplifyInfo {
32    /// Returns true if this Expr has boolean type
33    fn is_boolean_type(&self, expr: &Expr) -> Result<bool>;
34
35    /// Returns true of this expr is nullable (could possibly be NULL)
36    fn nullable(&self, expr: &Expr) -> Result<bool>;
37
38    /// Returns details needed for partial expression evaluation
39    fn execution_props(&self) -> &ExecutionProps;
40
41    /// Returns data type of this expr needed for determining optimized int type of a value
42    fn get_data_type(&self, expr: &Expr) -> Result<DataType>;
43}
44
45/// Provides simplification information based on DFSchema and
46/// [`ExecutionProps`]. This is the default implementation used by DataFusion
47///
48/// # Example
49/// See the `simplify_demo` in the [`expr_api` example]
50///
51/// [`expr_api` example]: https://github.com/apache/datafusion/blob/main/datafusion-examples/examples/expr_api.rs
52#[derive(Debug, Clone)]
53pub struct SimplifyContext<'a> {
54    schema: Option<DFSchemaRef>,
55    props: &'a ExecutionProps,
56}
57
58impl<'a> SimplifyContext<'a> {
59    /// Create a new SimplifyContext
60    pub fn new(props: &'a ExecutionProps) -> Self {
61        Self {
62            schema: None,
63            props,
64        }
65    }
66
67    /// Register a [`DFSchemaRef`] with this context
68    pub fn with_schema(mut self, schema: DFSchemaRef) -> Self {
69        self.schema = Some(schema);
70        self
71    }
72}
73
74impl SimplifyInfo for SimplifyContext<'_> {
75    /// Returns true if this Expr has boolean type
76    fn is_boolean_type(&self, expr: &Expr) -> Result<bool> {
77        if let Some(schema) = &self.schema {
78            if let Ok(DataType::Boolean) = expr.get_type(schema) {
79                return Ok(true);
80            }
81        }
82
83        Ok(false)
84    }
85
86    /// Returns true if expr is nullable
87    fn nullable(&self, expr: &Expr) -> Result<bool> {
88        let schema = self.schema.as_ref().ok_or_else(|| {
89            DataFusionError::Internal(
90                "attempt to get nullability without schema".to_string(),
91            )
92        })?;
93        expr.nullable(schema.as_ref())
94    }
95
96    /// Returns data type of this expr needed for determining optimized int type of a value
97    fn get_data_type(&self, expr: &Expr) -> Result<DataType> {
98        let schema = self.schema.as_ref().ok_or_else(|| {
99            DataFusionError::Internal(
100                "attempt to get data type without schema".to_string(),
101            )
102        })?;
103        expr.get_type(schema)
104    }
105
106    fn execution_props(&self) -> &ExecutionProps {
107        self.props
108    }
109}
110
111/// Was the expression simplified?
112#[derive(Debug)]
113pub enum ExprSimplifyResult {
114    /// The function call was simplified to an entirely new Expr
115    Simplified(Expr),
116    /// The function call could not be simplified, and the arguments
117    /// are return unmodified.
118    Original(Vec<Expr>),
119}