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