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