Skip to content

Commit aa8f139

Browse files
author
Brent Gardner
authored
Add insert/update/delete to LogicalPlan and add SQL planner support (#4902)
* Squash * PR feedback * PR feedback * DmlStatement * Cleanup * PR feedback * Fix insert
1 parent 279440b commit aa8f139

File tree

11 files changed

+389
-19
lines changed

11 files changed

+389
-19
lines changed

datafusion/core/src/physical_plan/planner.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1180,6 +1180,12 @@ impl DefaultPhysicalPlanner {
11801180
"Unsupported logical plan: CreateView".to_string(),
11811181
))
11821182
}
1183+
LogicalPlan::Dml(_) => {
1184+
// DataFusion is a read-only query engine, but also a library, so consumers may implement this
1185+
Err(DataFusionError::Internal(
1186+
"Unsupported logical plan: Write".to_string(),
1187+
))
1188+
}
11831189
LogicalPlan::SetVariable(_) => {
11841190
Err(DataFusionError::Internal(
11851191
"Unsupported logical plan: SetVariable must be root of the plan".to_string(),

datafusion/expr/src/lib.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -71,11 +71,11 @@ pub use logical_plan::{
7171
build_join_schema, union, wrap_projection_for_join_if_necessary, UNNAMED_TABLE,
7272
},
7373
Aggregate, CreateCatalog, CreateCatalogSchema, CreateExternalTable,
74-
CreateMemoryTable, CreateView, CrossJoin, Distinct, DropTable, DropView,
75-
EmptyRelation, Explain, Extension, Filter, Join, JoinConstraint, JoinType, Limit,
76-
LogicalPlan, LogicalPlanBuilder, Partitioning, PlanType, PlanVisitor, Projection,
77-
Repartition, SetVariable, Sort, StringifiedPlan, Subquery, SubqueryAlias, TableScan,
78-
ToStringifiedPlan, Union, UserDefinedLogicalNode, Values, Window,
74+
CreateMemoryTable, CreateView, CrossJoin, Distinct, DmlStatement, DropTable,
75+
DropView, EmptyRelation, Explain, Extension, Filter, Join, JoinConstraint, JoinType,
76+
Limit, LogicalPlan, LogicalPlanBuilder, Partitioning, PlanType, PlanVisitor,
77+
Projection, Repartition, SetVariable, Sort, StringifiedPlan, Subquery, SubqueryAlias,
78+
TableScan, ToStringifiedPlan, Union, UserDefinedLogicalNode, Values, Window, WriteOp,
7979
};
8080
pub use nullif::SUPPORTED_NULLIF_TYPES;
8181
pub use operator::Operator;

datafusion/expr/src/logical_plan/mod.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,11 @@ mod plan;
2323
pub use builder::{table_scan, LogicalPlanBuilder};
2424
pub use plan::{
2525
Aggregate, Analyze, CreateCatalog, CreateCatalogSchema, CreateExternalTable,
26-
CreateMemoryTable, CreateView, CrossJoin, Distinct, DropTable, DropView,
27-
EmptyRelation, Explain, Extension, Filter, Join, JoinConstraint, JoinType, Limit,
28-
LogicalPlan, Partitioning, PlanType, PlanVisitor, Prepare, Projection, Repartition,
29-
SetVariable, Sort, StringifiedPlan, Subquery, SubqueryAlias, TableScan,
30-
ToStringifiedPlan, Union, Values, Window,
26+
CreateMemoryTable, CreateView, CrossJoin, Distinct, DmlStatement, DropTable,
27+
DropView, EmptyRelation, Explain, Extension, Filter, Join, JoinConstraint, JoinType,
28+
Limit, LogicalPlan, Partitioning, PlanType, PlanVisitor, Prepare, Projection,
29+
Repartition, SetVariable, Sort, StringifiedPlan, Subquery, SubqueryAlias, TableScan,
30+
ToStringifiedPlan, Union, Values, Window, WriteOp,
3131
};
3232

3333
pub use display::display_schema;

datafusion/expr/src/logical_plan/plan.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,8 @@ pub enum LogicalPlan {
118118
SetVariable(SetVariable),
119119
/// Prepare a statement
120120
Prepare(Prepare),
121+
/// Insert / Update / Delete
122+
Dml(DmlStatement),
121123
}
122124

123125
impl LogicalPlan {
@@ -158,6 +160,7 @@ impl LogicalPlan {
158160
LogicalPlan::DropTable(DropTable { schema, .. }) => schema,
159161
LogicalPlan::DropView(DropView { schema, .. }) => schema,
160162
LogicalPlan::SetVariable(SetVariable { schema, .. }) => schema,
163+
LogicalPlan::Dml(DmlStatement { table_schema, .. }) => table_schema,
161164
}
162165
}
163166

@@ -218,6 +221,7 @@ impl LogicalPlan {
218221
LogicalPlan::DropTable(_)
219222
| LogicalPlan::DropView(_)
220223
| LogicalPlan::SetVariable(_) => vec![],
224+
LogicalPlan::Dml(DmlStatement { table_schema, .. }) => vec![table_schema],
221225
}
222226
}
223227

@@ -316,6 +320,7 @@ impl LogicalPlan {
316320
| LogicalPlan::Explain(_)
317321
| LogicalPlan::Union(_)
318322
| LogicalPlan::Distinct(_)
323+
| LogicalPlan::Dml(_)
319324
| LogicalPlan::Prepare(_) => Ok(()),
320325
}
321326
}
@@ -342,6 +347,7 @@ impl LogicalPlan {
342347
LogicalPlan::Distinct(Distinct { input }) => vec![input],
343348
LogicalPlan::Explain(explain) => vec![&explain.plan],
344349
LogicalPlan::Analyze(analyze) => vec![&analyze.input],
350+
LogicalPlan::Dml(write) => vec![&write.input],
345351
LogicalPlan::CreateMemoryTable(CreateMemoryTable { input, .. })
346352
| LogicalPlan::CreateView(CreateView { input, .. })
347353
| LogicalPlan::Prepare(Prepare { input, .. }) => {
@@ -544,6 +550,7 @@ impl LogicalPlan {
544550
}
545551
LogicalPlan::Explain(explain) => explain.plan.accept(visitor)?,
546552
LogicalPlan::Analyze(analyze) => analyze.input.accept(visitor)?,
553+
LogicalPlan::Dml(write) => write.input.accept(visitor)?,
547554
// plans without inputs
548555
LogicalPlan::TableScan { .. }
549556
| LogicalPlan::EmptyRelation(_)
@@ -929,6 +936,9 @@ impl LogicalPlan {
929936
}
930937
Ok(())
931938
}
939+
LogicalPlan::Dml(DmlStatement { table_name, op, .. }) => {
940+
write!(f, "Write: op=[{op}] table=[{table_name}]")
941+
}
932942
LogicalPlan::Filter(Filter {
933943
predicate: ref expr,
934944
..
@@ -1504,6 +1514,38 @@ pub struct CreateExternalTable {
15041514
pub options: HashMap<String, String>,
15051515
}
15061516

1517+
#[derive(Clone)]
1518+
pub enum WriteOp {
1519+
Insert,
1520+
Delete,
1521+
Update,
1522+
Ctas,
1523+
}
1524+
1525+
impl Display for WriteOp {
1526+
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1527+
match self {
1528+
WriteOp::Insert => write!(f, "Insert"),
1529+
WriteOp::Delete => write!(f, "Delete"),
1530+
WriteOp::Update => write!(f, "Update"),
1531+
WriteOp::Ctas => write!(f, "Ctas"),
1532+
}
1533+
}
1534+
}
1535+
1536+
/// The operator that modifies the content of a database (adapted from substrait WriteRel)
1537+
#[derive(Clone)]
1538+
pub struct DmlStatement {
1539+
/// The table name
1540+
pub table_name: OwnedTableReference,
1541+
/// The schema of the table (must align with Rel input)
1542+
pub table_schema: DFSchemaRef,
1543+
/// The type of operation to perform
1544+
pub op: WriteOp,
1545+
/// The relation that determines the tuples to add/remove/modify the schema must match with table_schema
1546+
pub input: Arc<LogicalPlan>,
1547+
}
1548+
15071549
/// Prepare a statement but do not execute it. Prepare statements can have 0 or more
15081550
/// `Expr::Placeholder` expressions that are filled in during execution
15091551
#[derive(Clone)]

datafusion/expr/src/utils.rs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ use crate::logical_plan::{
2727
SubqueryAlias, Union, Values, Window,
2828
};
2929
use crate::{
30-
BinaryExpr, Cast, Expr, ExprSchemable, LogicalPlan, LogicalPlanBuilder, Operator,
31-
TableScan, TryCast,
30+
BinaryExpr, Cast, DmlStatement, Expr, ExprSchemable, LogicalPlan, LogicalPlanBuilder,
31+
Operator, TableScan, TryCast,
3232
};
3333
use arrow::datatypes::{DataType, TimeUnit};
3434
use datafusion_common::{
@@ -489,6 +489,17 @@ pub fn from_plan(
489489
schema.clone(),
490490
)?))
491491
}
492+
LogicalPlan::Dml(DmlStatement {
493+
table_name,
494+
table_schema,
495+
op,
496+
..
497+
}) => Ok(LogicalPlan::Dml(DmlStatement {
498+
table_name: table_name.clone(),
499+
table_schema: table_schema.clone(),
500+
op: op.clone(),
501+
input: Arc::new(inputs[0].clone()),
502+
})),
492503
LogicalPlan::Values(Values { schema, .. }) => Ok(LogicalPlan::Values(Values {
493504
schema: schema.clone(),
494505
values: expr

datafusion/optimizer/src/common_subexpr_eliminate.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,7 @@ impl OptimizerRule for CommonSubexprEliminate {
239239
| LogicalPlan::SetVariable(_)
240240
| LogicalPlan::Distinct(_)
241241
| LogicalPlan::Extension(_)
242+
| LogicalPlan::Dml(_)
242243
| LogicalPlan::Prepare(_) => {
243244
// apply the optimization to all inputs of the plan
244245
utils::optimize_children(self, plan, config)?

datafusion/optimizer/src/push_down_projection.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,7 @@ fn optimize_plan(
410410
| LogicalPlan::DropView(_)
411411
| LogicalPlan::SetVariable(_)
412412
| LogicalPlan::CrossJoin(_)
413+
| LogicalPlan::Dml(_)
413414
| LogicalPlan::Extension { .. }
414415
| LogicalPlan::Prepare(_) => {
415416
let expr = plan.expressions();

datafusion/proto/src/logical_plan/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1345,6 +1345,9 @@ impl AsLogicalPlan for LogicalPlanNode {
13451345
LogicalPlan::SetVariable(_) => Err(proto_error(
13461346
"LogicalPlan serde is not yet implemented for DropView",
13471347
)),
1348+
LogicalPlan::Dml(_) => Err(proto_error(
1349+
"LogicalPlan serde is not yet implemented for Write",
1350+
)),
13481351
}
13491352
}
13501353
}

datafusion/sql/src/select.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,7 @@ impl<'a, S: ContextProvider> SqlToRel<'a, S> {
272272
}
273273
}
274274

275-
fn plan_from_tables(
275+
pub(crate) fn plan_from_tables(
276276
&self,
277277
mut from: Vec<TableWithJoins>,
278278
planner_context: &mut PlannerContext,

0 commit comments

Comments
 (0)