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}