Skip to content

Commit 4112116

Browse files
committed
Add MERGE INTO types to datafusion-expr
Add new types to support MERGE INTO DML statements: - MergeIntoOp: Carries ON condition and WHEN clauses - MergeIntoClause: Single WHEN clause (kind, predicate, action) - MergeIntoClauseKind: Matched/NotMatched/NotMatchedByTarget/NotMatchedBySource - MergeIntoAction: Update/Insert/Delete actions Add WriteOp::MergeInto variant to WriteOp enum.
1 parent 1f0232c commit 4112116

2 files changed

Lines changed: 64 additions & 2 deletions

File tree

datafusion/expr/src/logical_plan/dml.rs

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ use arrow::datatypes::{DataType, Field, Schema};
2525
use datafusion_common::file_options::file_type::FileType;
2626
use datafusion_common::{DFSchemaRef, TableReference};
2727

28-
use crate::{LogicalPlan, TableSource};
28+
use crate::{Expr, LogicalPlan, TableSource};
2929

3030
/// Operator that copies the contents of a database to file(s)
3131
#[derive(Clone)]
@@ -239,6 +239,8 @@ pub enum WriteOp {
239239
Ctas,
240240
/// `TRUNCATE` operation
241241
Truncate,
242+
/// `MERGE INTO` operation
243+
MergeInto(MergeIntoOp),
242244
}
243245

244246
impl WriteOp {
@@ -250,6 +252,7 @@ impl WriteOp {
250252
WriteOp::Update => "Update",
251253
WriteOp::Ctas => "Ctas",
252254
WriteOp::Truncate => "Truncate",
255+
WriteOp::MergeInto(_) => "MergeInto",
253256
}
254257
}
255258
}
@@ -291,6 +294,62 @@ impl Display for InsertOp {
291294
}
292295
}
293296

297+
/// Describes a MERGE INTO operation's parameters.
298+
///
299+
/// This is carried inside `WriteOp::MergeInto` and contains
300+
/// the ON condition and WHEN clauses that the TableProvider
301+
/// needs to execute the merge.
302+
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash)]
303+
pub struct MergeIntoOp {
304+
/// The join condition from `ON <expr>`.
305+
/// Kept as a general logical Expr; downstream providers
306+
/// (e.g., Iceberg) can decompose into column pairs if needed.
307+
pub on: Expr,
308+
/// The WHEN clauses, in the order they appeared in the SQL.
309+
pub clauses: Vec<MergeIntoClause>,
310+
}
311+
312+
/// A single WHEN clause within a MERGE INTO statement.
313+
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash)]
314+
pub struct MergeIntoClause {
315+
/// Whether this fires on matched or unmatched rows.
316+
pub kind: MergeIntoClauseKind,
317+
/// Optional additional predicate (`AND <expr>`).
318+
pub predicate: Option<Expr>,
319+
/// The action to take.
320+
pub action: MergeIntoAction,
321+
}
322+
323+
/// Which rows a MERGE WHEN clause applies to.
324+
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Hash)]
325+
pub enum MergeIntoClauseKind {
326+
/// WHEN MATCHED
327+
Matched,
328+
/// WHEN NOT MATCHED (synonymous with NOT MATCHED BY TARGET)
329+
NotMatched,
330+
/// WHEN NOT MATCHED BY TARGET
331+
NotMatchedByTarget,
332+
/// WHEN NOT MATCHED BY SOURCE
333+
NotMatchedBySource,
334+
}
335+
336+
/// The action for a single WHEN clause.
337+
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash)]
338+
pub enum MergeIntoAction {
339+
/// UPDATE SET col1 = expr1, col2 = expr2, ...
340+
/// Stored as (column_name, value_expr) pairs.
341+
Update(Vec<(String, Expr)>),
342+
/// INSERT (col1, col2, ...) VALUES (expr1, expr2, ...)
343+
/// `columns` may be empty (meaning all columns).
344+
/// `values` contains one expression per inserted column.
345+
Insert {
346+
columns: Vec<String>,
347+
values: Vec<Expr>,
348+
},
349+
/// DELETE (no additional data needed)
350+
Delete,
351+
}
352+
294353
fn make_count_schema() -> DFSchemaRef {
295354
Arc::new(
296355
Schema::new(vec![Field::new("count", DataType::UInt64, false)])

datafusion/expr/src/logical_plan/mod.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,10 @@ pub use ddl::{
3636
CreateFunctionBody, CreateIndex, CreateMemoryTable, CreateView, DdlStatement,
3737
DropCatalogSchema, DropFunction, DropTable, DropView, OperateFunctionArg,
3838
};
39-
pub use dml::{DmlStatement, WriteOp};
39+
pub use dml::{
40+
DmlStatement, MergeIntoAction, MergeIntoClause, MergeIntoClauseKind, MergeIntoOp,
41+
WriteOp,
42+
};
4043
pub use plan::{
4144
Aggregate, Analyze, ColumnUnnestList, DescribeTable, Distinct, DistinctOn,
4245
EmptyRelation, Explain, ExplainOption, Extension, FetchType, Filter, Join,

0 commit comments

Comments
 (0)