Skip to content

Commit a20b318

Browse files
authored
feat: support DEALLOCATE to remove prepared statements (#13327)
1 parent 221c85f commit a20b318

File tree

6 files changed

+97
-5
lines changed

6 files changed

+97
-5
lines changed

datafusion/core/src/execution/context/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -715,6 +715,12 @@ impl SessionContext {
715715
LogicalPlan::Statement(Statement::Execute(execute)) => {
716716
self.execute_prepared(execute)
717717
}
718+
LogicalPlan::Statement(Statement::Deallocate(deallocate)) => {
719+
self.state
720+
.write()
721+
.remove_prepared(deallocate.name.as_str())?;
722+
self.return_empty_dataframe()
723+
}
718724
plan => Ok(DataFrame::new(self.state(), plan)),
719725
}
720726
}

datafusion/core/src/execution/session_state.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -934,6 +934,17 @@ impl SessionState {
934934
pub(crate) fn get_prepared(&self, name: &str) -> Option<Arc<PreparedPlan>> {
935935
self.prepared_plans.get(name).map(Arc::clone)
936936
}
937+
938+
/// Remove the prepared plan with the given name.
939+
pub(crate) fn remove_prepared(
940+
&mut self,
941+
name: &str,
942+
) -> datafusion_common::Result<()> {
943+
match self.prepared_plans.remove(name) {
944+
Some(_) => Ok(()),
945+
None => exec_err!("Prepared statement '{}' does not exist", name),
946+
}
947+
}
937948
}
938949

939950
/// A builder to be used for building [`SessionState`]'s. Defaults will

datafusion/expr/src/logical_plan/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ pub use plan::{
4242
SubqueryAlias, TableScan, ToStringifiedPlan, Union, Unnest, Values, Window,
4343
};
4444
pub use statement::{
45-
Execute, Prepare, SetVariable, Statement, TransactionAccessMode,
45+
Deallocate, Execute, Prepare, SetVariable, Statement, TransactionAccessMode,
4646
TransactionConclusion, TransactionEnd, TransactionIsolationLevel, TransactionStart,
4747
};
4848

datafusion/expr/src/logical_plan/statement.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ pub enum Statement {
4848
Prepare(Prepare),
4949
/// Execute a prepared statement. This is used to implement SQL 'EXECUTE'.
5050
Execute(Execute),
51+
/// Deallocate a prepared statement.
52+
/// This is used to implement SQL 'DEALLOCATE'.
53+
Deallocate(Deallocate),
5154
}
5255

5356
impl Statement {
@@ -65,6 +68,7 @@ impl Statement {
6568
Statement::SetVariable(_) => "SetVariable",
6669
Statement::Prepare(_) => "Prepare",
6770
Statement::Execute(_) => "Execute",
71+
Statement::Deallocate(_) => "Deallocate",
6872
}
6973
}
7074

@@ -167,6 +171,9 @@ impl Statement {
167171
expr_vec_fmt!(parameters)
168172
)
169173
}
174+
Statement::Deallocate(Deallocate { name }) => {
175+
write!(f, "Deallocate: {}", name)
176+
}
170177
}
171178
}
172179
}
@@ -245,3 +252,10 @@ pub struct Execute {
245252
/// The execute parameters
246253
pub parameters: Vec<Expr>,
247254
}
255+
256+
/// Deallocate a prepared statement.
257+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Hash)]
258+
pub struct Deallocate {
259+
/// The name of the prepared statement to deallocate
260+
pub name: String,
261+
}

datafusion/sql/src/statement.rs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,10 @@ use datafusion_expr::utils::expr_to_columns;
4646
use datafusion_expr::{
4747
cast, col, Analyze, CreateCatalog, CreateCatalogSchema,
4848
CreateExternalTable as PlanCreateExternalTable, CreateFunction, CreateFunctionBody,
49-
CreateIndex as PlanCreateIndex, CreateMemoryTable, CreateView, DescribeTable,
50-
DmlStatement, DropCatalogSchema, DropFunction, DropTable, DropView, EmptyRelation,
51-
Execute, Explain, Expr, ExprSchemable, Filter, LogicalPlan, LogicalPlanBuilder,
52-
OperateFunctionArg, PlanType, Prepare, SetVariable, SortExpr,
49+
CreateIndex as PlanCreateIndex, CreateMemoryTable, CreateView, Deallocate,
50+
DescribeTable, DmlStatement, DropCatalogSchema, DropFunction, DropTable, DropView,
51+
EmptyRelation, Execute, Explain, Expr, ExprSchemable, Filter, LogicalPlan,
52+
LogicalPlanBuilder, OperateFunctionArg, PlanType, Prepare, SetVariable, SortExpr,
5353
Statement as PlanStatement, ToStringifiedPlan, TransactionAccessMode,
5454
TransactionConclusion, TransactionEnd, TransactionIsolationLevel, TransactionStart,
5555
Volatility, WriteOp,
@@ -665,6 +665,15 @@ impl<'a, S: ContextProvider> SqlToRel<'a, S> {
665665
parameters,
666666
})))
667667
}
668+
Statement::Deallocate {
669+
name,
670+
// Similar to PostgreSQL, the PREPARE keyword is ignored
671+
prepare: _,
672+
} => Ok(LogicalPlan::Statement(PlanStatement::Deallocate(
673+
Deallocate {
674+
name: ident_to_string(&name),
675+
},
676+
))),
668677

669678
Statement::ShowTables {
670679
extended,

datafusion/sqllogictest/test_files/prepare.slt

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@ PREPARE my_plan AS SELECT $1;
6464
statement error Prepared statement \'my_plan\' does not exist
6565
EXECUTE my_plan('Foo', 'Bar');
6666

67+
# deallocate a non-existing plan
68+
statement error Prepared statement \'my_plan\' does not exist
69+
DEALLOCATE my_plan;
70+
6771
statement ok
6872
PREPARE my_plan(STRING, STRING) AS SELECT * FROM (VALUES(1, $1), (2, $2)) AS t (num, letter);
6973

@@ -77,6 +81,28 @@ EXECUTE my_plan('Foo', 'Bar');
7781
statement error Prepared statement \'my_plan\' already exists
7882
PREPARE my_plan(STRING, STRING) AS SELECT * FROM (VALUES(1, $1), (2, $2)) AS t (num, letter);
7983

84+
# deallocate a plan
85+
statement ok
86+
DEALLOCATE my_plan;
87+
88+
# can't EXECUTE a deallocated plan
89+
statement error Prepared statement \'my_plan\' does not exist
90+
EXECUTE my_plan('Foo', 'Bar');
91+
92+
# re-prepare a deallocated plan
93+
statement ok
94+
PREPARE my_plan(STRING, STRING) AS SELECT * FROM (VALUES(1, $1), (2, $2)) AS t (num, letter);
95+
96+
query IT
97+
EXECUTE my_plan('Foo', 'Bar');
98+
----
99+
1 Foo
100+
2 Bar
101+
102+
# deallocate with the PREPARE keyword
103+
statement ok
104+
DEALLOCATE PREPARE my_plan;
105+
80106
statement error Prepare specifies 1 data types but query has 0 parameters
81107
PREPARE my_plan(INT) AS SELECT id, age FROM person WHERE age = 10;
82108

@@ -89,6 +115,9 @@ EXECUTE my_plan2;
89115
----
90116
1 20
91117

118+
statement ok
119+
DEALLOCATE my_plan2;
120+
92121
statement ok
93122
PREPARE my_plan3(INT) AS SELECT $1;
94123

@@ -97,6 +126,9 @@ EXECUTE my_plan3(10);
97126
----
98127
10
99128

129+
statement ok
130+
DEALLOCATE my_plan3;
131+
100132
statement ok
101133
PREPARE my_plan4(INT) AS SELECT 1 + $1;
102134

@@ -105,6 +137,9 @@ EXECUTE my_plan4(10);
105137
----
106138
11
107139

140+
statement ok
141+
DEALLOCATE my_plan4;
142+
108143
statement ok
109144
PREPARE my_plan5(INT, DOUBLE) AS SELECT 1 + $1 + $2;
110145

@@ -113,6 +148,9 @@ EXECUTE my_plan5(10, 20.5);
113148
----
114149
31.5
115150

151+
statement ok
152+
DEALLOCATE my_plan5;
153+
116154
statement ok
117155
PREPARE my_plan6(INT) AS SELECT id, age FROM person WHERE age = $1;
118156

@@ -140,6 +178,9 @@ EXECUTE my_plan6('foo');
140178
statement error Unsupported parameter type
141179
EXECUTE my_plan6(10 + 20);
142180

181+
statement ok
182+
DEALLOCATE my_plan6;
183+
143184
statement ok
144185
PREPARE my_plan7(INT, STRING, DOUBLE, INT, DOUBLE, STRING)
145186
AS
@@ -150,6 +191,9 @@ EXECUTE my_plan7(10, 'jane', 99999.45, 20, 200000.45, 'foo');
150191
----
151192
1 20 foo
152193

194+
statement ok
195+
DEALLOCATE my_plan7;
196+
153197
statement ok
154198
PREPARE my_plan8(INT, DOUBLE, DOUBLE, DOUBLE)
155199
AS
@@ -161,6 +205,9 @@ EXECUTE my_plan8(100000, 99999.45, 100000.45, 200000.45);
161205
----
162206
1 20
163207

208+
statement ok
209+
DEALLOCATE my_plan8;
210+
164211
statement ok
165212
PREPARE my_plan9(STRING, STRING) AS SELECT * FROM (VALUES(1, $1), (2, $2)) AS t (num, letter);
166213

@@ -170,6 +217,8 @@ EXECUTE my_plan9('Foo', 'Bar');
170217
1 Foo
171218
2 Bar
172219

220+
statement ok
221+
DEALLOCATE my_plan9;
173222

174223
# Test issue: https://github.com/apache/datafusion/issues/12294
175224
# prepare argument is in the LIMIT clause
@@ -196,6 +245,9 @@ EXECUTE get_N_rand_ints_from_last_run(2);
196245
1
197246
1
198247

248+
statement ok
249+
DEALLOCATE get_N_rand_ints_from_last_run;
250+
199251
statement ok
200252
DROP TABLE test;
201253

0 commit comments

Comments
 (0)