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}