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}