Skip to main content

datafusion_expr/
execution_props.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
18use crate::var_provider::{VarProvider, VarType};
19use chrono::{DateTime, Utc};
20use datafusion_common::HashMap;
21use datafusion_common::alias::AliasGenerator;
22use datafusion_common::config::ConfigOptions;
23use std::sync::Arc;
24
25/// Holds properties and scratch state used while optimizing a [`LogicalPlan`]
26/// and translating it into an executable physical plan, such as the statement
27/// start time used during simplification.
28///
29/// An [`ExecutionProps`] is created each time a `LogicalPlan` is
30/// prepared for execution (optimized). If the same plan is optimized
31/// multiple times, a new `ExecutionProps` is created each time.
32///
33/// It is important that this structure be cheap to create as it is
34/// done so during predicate pruning and expression simplification
35///
36/// # Relationship with [`TaskContext`]
37///
38/// [`ExecutionProps`] is intentionally distinct from [`TaskContext`].
39/// It is used while optimizing a logical plan and constructing physical
40/// expressions and physical plans, before physical operators are run.
41///
42/// [`TaskContext`] is the runtime context passed to physical operators during
43/// physical-plan execution.
44///
45/// Keeping these structures separate avoids threading execution/runtime state
46/// through planning APIs, and avoids making execution depend on planner-only
47/// scratch state.
48///
49/// [`TaskContext`]: https://docs.rs/datafusion/latest/datafusion/execution/struct.TaskContext.html
50/// [`LogicalPlan`]: crate::LogicalPlan
51#[derive(Clone, Debug)]
52pub struct ExecutionProps {
53    /// The time at which the query execution started. If `None`,
54    /// functions like `now()` will not be simplified during optimization.
55    pub query_execution_start_time: Option<DateTime<Utc>>,
56    /// Alias generator used by subquery optimizer rules
57    pub alias_generator: Arc<AliasGenerator>,
58    /// Snapshot of config options when the query started
59    pub config_options: Option<Arc<ConfigOptions>>,
60    /// Providers for scalar variables
61    pub var_providers: Option<HashMap<VarType, Arc<dyn VarProvider + Send + Sync>>>,
62}
63
64impl Default for ExecutionProps {
65    fn default() -> Self {
66        Self::new()
67    }
68}
69
70impl ExecutionProps {
71    /// Creates a new execution props
72    pub fn new() -> Self {
73        ExecutionProps {
74            query_execution_start_time: None,
75            alias_generator: Arc::new(AliasGenerator::new()),
76            config_options: None,
77            var_providers: None,
78        }
79    }
80
81    /// Set the query execution start time to use
82    pub fn with_query_execution_start_time(
83        mut self,
84        query_execution_start_time: DateTime<Utc>,
85    ) -> Self {
86        self.query_execution_start_time = Some(query_execution_start_time);
87        self
88    }
89
90    #[deprecated(since = "50.0.0", note = "Use mark_start_execution instead")]
91    pub fn start_execution(&mut self) -> &Self {
92        let default_config = Arc::new(ConfigOptions::default());
93        self.mark_start_execution(default_config)
94    }
95
96    /// Marks the execution of query started timestamp.
97    /// This also instantiates a new alias generator.
98    pub fn mark_start_execution(&mut self, config_options: Arc<ConfigOptions>) -> &Self {
99        self.query_execution_start_time = Some(Utc::now());
100        self.alias_generator = Arc::new(AliasGenerator::new());
101        self.config_options = Some(config_options);
102        &*self
103    }
104
105    /// Registers a variable provider, returning the existing provider, if any
106    pub fn add_var_provider(
107        &mut self,
108        var_type: VarType,
109        provider: Arc<dyn VarProvider + Send + Sync>,
110    ) -> Option<Arc<dyn VarProvider + Send + Sync>> {
111        let mut var_providers = self.var_providers.take().unwrap_or_default();
112
113        let old_provider = var_providers.insert(var_type, provider);
114
115        self.var_providers = Some(var_providers);
116
117        old_provider
118    }
119
120    /// Returns the provider for the `var_type`, if any
121    #[expect(clippy::needless_pass_by_value)]
122    pub fn get_var_provider(
123        &self,
124        var_type: VarType,
125    ) -> Option<Arc<dyn VarProvider + Send + Sync>> {
126        self.var_providers
127            .as_ref()
128            .and_then(|var_providers| var_providers.get(&var_type).cloned())
129    }
130
131    /// Returns the configuration properties for this execution
132    /// if the execution has started
133    pub fn config_options(&self) -> Option<&Arc<ConfigOptions>> {
134        self.config_options.as_ref()
135    }
136}
137
138#[cfg(test)]
139mod test {
140    use super::*;
141
142    #[test]
143    fn debug() {
144        let props = ExecutionProps::new();
145        assert_eq!(
146            "ExecutionProps { query_execution_start_time: None, alias_generator: AliasGenerator { next_id: 1 }, config_options: None, var_providers: None }",
147            format!("{props:?}")
148        );
149    }
150}