Skip to main content

datafusion_expr/logical_plan/
statement.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 arrow::datatypes::FieldRef;
19use datafusion_common::metadata::format_type_and_metadata;
20use datafusion_common::{DFSchema, DFSchemaRef};
21use itertools::Itertools as _;
22use std::fmt::{self, Display};
23use std::sync::Arc;
24
25use crate::{Expr, LogicalPlan, expr_vec_fmt};
26
27/// Various types of Statements.
28///
29/// # Transactions:
30///
31/// While DataFusion does not offer support transactions, it provides
32/// [`LogicalPlan`] support to assist building database systems
33/// using DataFusion
34#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash)]
35pub enum Statement {
36    // Begin a transaction
37    TransactionStart(TransactionStart),
38    // Commit or rollback a transaction
39    TransactionEnd(TransactionEnd),
40    /// Set a Variable
41    SetVariable(SetVariable),
42    /// Reset a Variable
43    ResetVariable(ResetVariable),
44    /// Prepare a statement and find any bind parameters
45    /// (e.g. `?`). This is used to implement SQL-prepared statements.
46    Prepare(Prepare),
47    /// Execute a prepared statement. This is used to implement SQL 'EXECUTE'.
48    Execute(Execute),
49    /// Deallocate a prepared statement.
50    /// This is used to implement SQL 'DEALLOCATE'.
51    Deallocate(Deallocate),
52}
53
54impl Statement {
55    /// Get a reference to the logical plan's schema
56    pub fn schema(&self) -> &DFSchemaRef {
57        // Statements have an unchanging empty schema.
58        DFSchema::empty_ref()
59    }
60
61    /// Return a descriptive string describing the type of this
62    /// [`Statement`]
63    pub fn name(&self) -> &str {
64        match self {
65            Statement::TransactionStart(_) => "TransactionStart",
66            Statement::TransactionEnd(_) => "TransactionEnd",
67            Statement::SetVariable(_) => "SetVariable",
68            Statement::ResetVariable(_) => "ResetVariable",
69            Statement::Prepare(_) => "Prepare",
70            Statement::Execute(_) => "Execute",
71            Statement::Deallocate(_) => "Deallocate",
72        }
73    }
74
75    /// Returns input LogicalPlans in the current `Statement`.
76    pub(super) fn inputs(&self) -> Vec<&LogicalPlan> {
77        match self {
78            Statement::Prepare(Prepare { input, .. }) => vec![input.as_ref()],
79            _ => vec![],
80        }
81    }
82
83    /// Return a `format`able structure with the a human readable
84    /// description of this LogicalPlan node per node, not including
85    /// children.
86    ///
87    /// See [crate::LogicalPlan::display] for an example
88    pub fn display(&self) -> impl Display + '_ {
89        struct Wrapper<'a>(&'a Statement);
90        impl Display for Wrapper<'_> {
91            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
92                match self.0 {
93                    Statement::TransactionStart(TransactionStart {
94                        access_mode,
95                        isolation_level,
96                        ..
97                    }) => {
98                        write!(f, "TransactionStart: {access_mode:?} {isolation_level:?}")
99                    }
100                    Statement::TransactionEnd(TransactionEnd {
101                        conclusion,
102                        chain,
103                        ..
104                    }) => {
105                        write!(f, "TransactionEnd: {conclusion:?} chain:={chain}")
106                    }
107                    Statement::SetVariable(SetVariable {
108                        variable, value, ..
109                    }) => {
110                        write!(f, "SetVariable: set {variable:?} to {value:?}")
111                    }
112                    Statement::ResetVariable(ResetVariable { variable }) => {
113                        write!(f, "ResetVariable: reset {variable:?}")
114                    }
115                    Statement::Prepare(Prepare { name, fields, .. }) => {
116                        write!(
117                            f,
118                            "Prepare: {name:?} [{}]",
119                            fields
120                                .iter()
121                                .map(|f| format_type_and_metadata(
122                                    f.data_type(),
123                                    Some(f.metadata())
124                                ))
125                                .join(", ")
126                        )
127                    }
128                    Statement::Execute(Execute {
129                        name, parameters, ..
130                    }) => {
131                        write!(
132                            f,
133                            "Execute: {} params=[{}]",
134                            name,
135                            expr_vec_fmt!(parameters)
136                        )
137                    }
138                    Statement::Deallocate(Deallocate { name }) => {
139                        write!(f, "Deallocate: {name}")
140                    }
141                }
142            }
143        }
144        Wrapper(self)
145    }
146}
147
148/// Indicates if a transaction was committed or aborted
149#[derive(Clone, PartialEq, Eq, PartialOrd, Hash, Debug)]
150pub enum TransactionConclusion {
151    Commit,
152    Rollback,
153}
154
155/// Indicates if this transaction is allowed to write
156#[derive(Clone, PartialEq, Eq, PartialOrd, Hash, Debug)]
157pub enum TransactionAccessMode {
158    ReadOnly,
159    ReadWrite,
160}
161
162/// Indicates ANSI transaction isolation level
163#[derive(Clone, PartialEq, Eq, PartialOrd, Hash, Debug)]
164pub enum TransactionIsolationLevel {
165    ReadUncommitted,
166    ReadCommitted,
167    RepeatableRead,
168    Serializable,
169    Snapshot,
170}
171
172/// Indicator that the following statements should be committed or rolled back atomically
173#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Hash)]
174pub struct TransactionStart {
175    /// indicates if transaction is allowed to write
176    pub access_mode: TransactionAccessMode,
177    // indicates ANSI isolation level
178    pub isolation_level: TransactionIsolationLevel,
179}
180
181/// Indicator that any current transaction should be terminated
182#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Hash)]
183pub struct TransactionEnd {
184    /// whether the transaction committed or aborted
185    pub conclusion: TransactionConclusion,
186    /// if specified a new transaction is immediately started with same characteristics
187    pub chain: bool,
188}
189
190/// Set a Variable's value -- value in
191/// [`ConfigOptions`](datafusion_common::config::ConfigOptions)
192#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Hash)]
193pub struct SetVariable {
194    /// The variable name
195    pub variable: String,
196    /// The value to set
197    pub value: String,
198}
199
200/// Reset a configuration variable to its default
201#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash)]
202pub struct ResetVariable {
203    /// The variable name
204    pub variable: String,
205}
206/// Prepare a statement but do not execute it. Prepare statements can have 0 or more
207/// `Expr::Placeholder` expressions that are filled in during execution
208#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash)]
209pub struct Prepare {
210    /// The name of the statement
211    pub name: String,
212    /// Data types of the parameters ([`Expr::Placeholder`])
213    pub fields: Vec<FieldRef>,
214    /// The logical plan of the statements
215    pub input: Arc<LogicalPlan>,
216}
217
218/// Execute a prepared statement.
219#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Hash)]
220pub struct Execute {
221    /// The name of the prepared statement to execute
222    pub name: String,
223    /// The execute parameters
224    pub parameters: Vec<Expr>,
225}
226
227/// Deallocate a prepared statement.
228#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Hash)]
229pub struct Deallocate {
230    /// The name of the prepared statement to deallocate
231    pub name: String,
232}