Skip to content

feat: Add WHEN MATCHED THEN DELETE support to MERGE INTO statement (#27409)#27409

Merged
hantangwangd merged 1 commit intoprestodb:masterfrom
apurva-meta:export-D97683467
Mar 31, 2026
Merged

feat: Add WHEN MATCHED THEN DELETE support to MERGE INTO statement (#27409)#27409
hantangwangd merged 1 commit intoprestodb:masterfrom
apurva-meta:export-D97683467

Conversation

@apurva-meta
Copy link
Copy Markdown
Contributor

@apurva-meta apurva-meta commented Mar 23, 2026

Summary:

Implements the missing WHEN MATCHED THEN DELETE clause for the SQL-standard MERGE INTO statement in Presto. The existing MERGE implementation supports WHEN MATCHED THEN UPDATE and WHEN NOT MATCHED THEN INSERT, but lacked the DELETE case. This completes the SQL:2011 MERGE specification.

Changes across the full stack:

  • Grammar (SqlBase.g4): Added mergeDelete alternative to mergeCase rule
  • AST (MergeDelete.java): New node extending MergeCase with empty column/expression lists
  • Parser (AstBuilder): ANTLR parse tree to MergeDelete AST conversion
  • Visitors (AstVisitor, DefaultTraversalVisitor): visitMergeDelete dispatch
  • Formatter (SqlFormatter): SQL text generation for WHEN MATCHED THEN DELETE
  • Planner (QueryPlanner): MergeDelete maps to DELETE_OPERATION_NUMBER (=2)
  • Analyzer (StatementAnalyzer): checkCanDeleteFromTable access control
  • Tests (TestSqlParser): Parser round-trip test for MERGE with DELETE clause
  • Tests (IcebergDistributedTestBase): 3 integration tests for MERGE DELETE with Iceberg connector

The execution engine (DeleteAndInsertMergeProcessor) and SPI (ConnectorMergeSink) already handle DELETE_OPERATION_NUMBER, so no changes were needed there.

== RELEASE NOTES ==

General Changes

  • Add support for WHEN MATCHED THEN DELETE clause in MERGE INTO statements, completing the SQL:2011 MERGE specification. The existing MERGE implementation supported WHEN MATCHED THEN UPDATE and WHEN NOT MATCHED THEN INSERT but lacked the DELETE case.

Reviewed By: xiaoxmeng

Differential Revision: D97683467

@sourcery-ai
Copy link
Copy Markdown
Contributor

sourcery-ai bot commented Mar 23, 2026

Reviewer's Guide

Adds full support for the SQL-standard WHEN MATCHED THEN DELETE clause in MERGE INTO by extending the grammar, AST, planner, analyzer, formatter, and tests, including new Iceberg integration tests for delete-only and delete-with-insert MERGE scenarios.

Sequence diagram for MERGE INTO with WHEN MATCHED THEN DELETE

sequenceDiagram
    actor User
    participant PrestoCoordinator
    participant SqlParser
    participant AstBuilder
    participant StatementAnalyzer
    participant QueryPlanner
    participant ExecutionEngine
    participant Connector

    User->>PrestoCoordinator: Submit MERGE INTO ... WHEN MATCHED THEN DELETE

    PrestoCoordinator->>SqlParser: Parse SQL text
    SqlParser-->>AstBuilder: Parse tree with mergeDelete alternative
    AstBuilder->>AstBuilder: visitMergeDelete(context)
    AstBuilder-->>PrestoCoordinator: Merge AST containing MergeDelete case

    PrestoCoordinator->>StatementAnalyzer: Analyze MERGE statement
    StatementAnalyzer->>StatementAnalyzer: Collect merge cases
    StatementAnalyzer->>StatementAnalyzer: Detect MergeDelete case
    StatementAnalyzer->>StatementAnalyzer: accessControl.checkCanDeleteFromTable(targetTable)
    StatementAnalyzer-->>PrestoCoordinator: Analyzed MERGE with delete permission verified

    PrestoCoordinator->>QueryPlanner: Plan MERGE execution
    QueryPlanner->>QueryPlanner: getMergeCaseOperationNumber(MergeDelete)
    QueryPlanner-->>PrestoCoordinator: DELETE_OPERATION_NUMBER

    PrestoCoordinator->>ExecutionEngine: Create DeleteAndInsertMergeProcessor
    ExecutionEngine->>Connector: Open ConnectorMergeSink with delete support
    Connector-->>ExecutionEngine: MergeSink ready

    ExecutionEngine->>ExecutionEngine: Apply DELETE_OPERATION_NUMBER for matched rows
    ExecutionEngine->>Connector: Execute delete operations for matched rows
    Connector-->>ExecutionEngine: Delete operations committed

    ExecutionEngine-->>PrestoCoordinator: MERGE with delete completed
    PrestoCoordinator-->>User: MERGE statement finished successfully
Loading

Class diagram for MergeDelete integration into MERGE AST and visitors

classDiagram
    class Node {
    }

    class MergeCase {
        +List~Identifier~ getSetColumns()
        +List~Expression~ getSetExpressions()
    }

    class MergeUpdate {
        +List~Identifier~ getSetColumns()
        +List~Expression~ getSetExpressions()
    }

    class MergeInsert {
        +List~Identifier~ getSetColumns()
        +List~Expression~ getSetExpressions()
    }

    class MergeDelete {
        +MergeDelete()
        +MergeDelete(NodeLocation location)
        +MergeDelete(Optional~NodeLocation~ location)
        +List~Identifier~ getSetColumns()
        +List~Expression~ getSetExpressions()
        +List~Node~ getChildren()
        +int hashCode()
        +boolean equals(Object obj)
        +String toString()
    }

    class AstVisitor {
        +R visitMergeCase(MergeCase node, C context)
        +R visitMergeUpdate(MergeUpdate node, C context)
        +R visitMergeInsert(MergeInsert node, C context)
        +R visitMergeDelete(MergeDelete node, C context)
    }

    class DefaultTraversalVisitor {
        +R visitMergeUpdate(MergeUpdate node, C context)
        +R visitMergeDelete(MergeDelete node, C context)
    }

    class SqlFormatter_Formatter {
        +Void visitMergeUpdate(MergeUpdate node, Integer indent)
        +Void visitMergeDelete(MergeDelete node, Integer indent)
        -Void appendMergeCaseWhen(boolean matched)
    }

    class QueryPlanner {
        -static int getMergeCaseOperationNumber(MergeCase mergeCase)
    }

    class StatementAnalyzer {
        -void analyzeMergeAccessControl(Merge node)
    }

    Node <|-- MergeCase
    MergeCase <|-- MergeUpdate
    MergeCase <|-- MergeInsert
    MergeCase <|-- MergeDelete

    MergeCase ..> Identifier
    MergeCase ..> Expression
    MergeDelete ..> NodeLocation
    MergeDelete ..> AstVisitor

    AstVisitor <.. MergeDelete : accept(visitor, context)
    DefaultTraversalVisitor <|-- StatementAnalyzer

    SqlFormatter_Formatter ..> MergeUpdate
    SqlFormatter_Formatter ..> MergeDelete

    QueryPlanner ..> MergeCase

    StatementAnalyzer ..> MergeDelete
    StatementAnalyzer ..> MergeInsert
    StatementAnalyzer ..> MergeUpdate
Loading

File-Level Changes

Change Details Files
Extend MERGE grammar and AST to represent WHEN MATCHED THEN DELETE cases.
  • Add a mergeDelete alternative to the mergeCase rule so WHEN MATCHED THEN DELETE is parsed as a distinct case.
  • Introduce a MergeDelete AST node extending MergeCase with no set columns or expressions, including equality, hashing, and visitor integration.
  • Wire MergeDelete construction into the AstBuilder so ANTLR mergeDelete contexts produce MergeDelete nodes.
presto-parser/src/main/antlr4/com/facebook/presto/sql/parser/SqlBase.g4
presto-parser/src/main/java/com/facebook/presto/sql/parser/AstBuilder.java
presto-parser/src/main/java/com/facebook/presto/sql/tree/MergeDelete.java
Integrate MergeDelete with existing AST visitor and formatting infrastructure.
  • Add visitMergeDelete to AstVisitor so MergeDelete participates in MergeCase polymorphism.
  • Implement a no-op visitMergeDelete in DefaultTraversalVisitor to preserve traversal behavior.
  • Extend SqlFormatter to pretty-print WHEN MATCHED THEN DELETE merge cases via visitMergeDelete and existing helper methods.
presto-parser/src/main/java/com/facebook/presto/sql/tree/AstVisitor.java
presto-parser/src/main/java/com/facebook/presto/sql/tree/DefaultTraversalVisitor.java
presto-parser/src/main/java/com/facebook/presto/sql/SqlFormatter.java
Make the planner and analyzer understand delete merge cases and enforce delete privileges.
  • Map MergeDelete cases to DELETE_OPERATION_NUMBER in the QueryPlanner merge case operation resolver.
  • Add an access-control check in StatementAnalyzer to require delete privileges on the target table when a MergeDelete case is present.
presto-main-base/src/main/java/com/facebook/presto/sql/planner/QueryPlanner.java
presto-main-base/src/main/java/com/facebook/presto/sql/analyzer/StatementAnalyzer.java
Add parser and end-to-end tests for MERGE with WHEN MATCHED THEN DELETE, including Iceberg connector coverage.
  • Add a TestSqlParser round-trip test ensuring MERGE with WHEN MATCHED THEN DELETE and an INSERT branch builds the expected Merge AST (MergeDelete followed by MergeInsert).
  • Introduce IcebergDistributedTestBase tests for delete-with-insert, delete-only, and partitioned delete MERGE operations, verifying affected row counts and final table contents.
presto-parser/src/test/java/com/facebook/presto/sql/parser/TestSqlParser.java
presto-iceberg/src/test/java/com/facebook/presto/iceberg/IcebergDistributedTestBase.java

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@apurva-meta apurva-meta changed the title [presto] Add WHEN MATCHED THEN DELETE support to MERGE INTO statement feat: [presto] Add WHEN MATCHED THEN DELETE support to MERGE INTO statement Mar 23, 2026
@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 23, 2026

Codenotify: Notifying subscribers in CODENOTIFY files for diff fb302b1...bb7fb1b.

Notify File(s)
@aditi-pandit presto-parser/src/main/antlr4/com/facebook/presto/sql/parser/SqlBase.g4
@elharo presto-parser/src/main/antlr4/com/facebook/presto/sql/parser/SqlBase.g4
@kaikalur presto-parser/src/main/antlr4/com/facebook/presto/sql/parser/SqlBase.g4
@rschlussel presto-parser/src/main/antlr4/com/facebook/presto/sql/parser/SqlBase.g4

Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've reviewed your changes and they look great!


Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@steveburnett
Copy link
Copy Markdown
Contributor

Please add a release note - or NO RELEASE NOTE - following the Release Notes Guidelines to pass the failing but not required CI check.

Please edit the PR title to follow semantic commit style to pass the failing and required CI check. See the failure in the test for advice.
If you can't edit the PR title, let us know and we can help.

@meta-codesync meta-codesync bot changed the title feat: [presto] Add WHEN MATCHED THEN DELETE support to MERGE INTO statement Feat: [presto] Add WHEN MATCHED THEN DELETE support to MERGE INTO statement (#27409) Mar 23, 2026
apurva-meta added a commit to apurva-meta/presto that referenced this pull request Mar 23, 2026
…tement (prestodb#27409)

Summary:

Implements the missing WHEN MATCHED THEN DELETE clause for the SQL-standard MERGE INTO statement in Presto. The existing MERGE implementation supports WHEN MATCHED THEN UPDATE and WHEN NOT MATCHED THEN INSERT, but lacked the DELETE case. This completes the SQL:2011 MERGE specification.

== RELEASE NOTES ==
- Grammar (SqlBase.g4): Added mergeDelete alternative to mergeCase rule
- AST (MergeDelete.java): New node extending MergeCase with empty column/expression lists
- Parser (AstBuilder): ANTLR parse tree to MergeDelete AST conversion
- Visitors (AstVisitor, DefaultTraversalVisitor): visitMergeDelete dispatch
- Formatter (SqlFormatter): SQL text generation for WHEN MATCHED THEN DELETE
- Planner (QueryPlanner): MergeDelete maps to DELETE_OPERATION_NUMBER (=2)
- Analyzer (StatementAnalyzer): checkCanDeleteFromTable access control
- Tests (TestSqlParser): Parser round-trip test for MERGE with DELETE clause

The execution engine (DeleteAndInsertMergeProcessor) and SPI (ConnectorMergeSink) already handle DELETE_OPERATION_NUMBER, so no changes were needed there.

Differential Revision: D97683467
@apurva-meta apurva-meta force-pushed the export-D97683467 branch 2 times, most recently from 98c77c4 to ba79d08 Compare March 26, 2026 21:17
@meta-codesync meta-codesync bot changed the title Feat: [presto] Add WHEN MATCHED THEN DELETE support to MERGE INTO statement (#27409) feat: Add WHEN MATCHED THEN DELETE support to MERGE INTO statement Mar 26, 2026
@meta-codesync meta-codesync bot changed the title feat: Add WHEN MATCHED THEN DELETE support to MERGE INTO statement feat: Add WHEN MATCHED THEN DELETE support to MERGE INTO statement (#27409) Mar 27, 2026
apurva-meta added a commit to apurva-meta/presto that referenced this pull request Mar 27, 2026
…restodb#27409)

Summary:

Implements the missing WHEN MATCHED THEN DELETE clause for the SQL-standard MERGE INTO statement in Presto. The existing MERGE implementation supports WHEN MATCHED THEN UPDATE and WHEN NOT MATCHED THEN INSERT, but lacked the DELETE case. This completes the SQL:2011 MERGE specification. This is needed for Iceberg support.

Changes across the full stack:
- Grammar (SqlBase.g4): Added mergeDelete alternative to mergeCase rule
- AST (MergeDelete.java): New node extending MergeCase with empty column/expression lists
- Parser (AstBuilder): ANTLR parse tree to MergeDelete AST conversion
- Visitors (AstVisitor, DefaultTraversalVisitor): visitMergeDelete dispatch
- Formatter (SqlFormatter): SQL text generation for WHEN MATCHED THEN DELETE
- Planner (QueryPlanner): MergeDelete maps to DELETE_OPERATION_NUMBER (=2)
- Analyzer (StatementAnalyzer): checkCanDeleteFromTable access control
- Tests (TestSqlParser): Parser round-trip test for MERGE with DELETE clause
- Tests (IcebergDistributedTestBase): 3 integration tests for MERGE DELETE with Iceberg connector

The execution engine (DeleteAndInsertMergeProcessor) and SPI (ConnectorMergeSink) already handle DELETE_OPERATION_NUMBER, so no changes were needed there.

== Key Benefits of MERGE INTO vs. UPDATE/DELETE in Iceberg ==

- **Atomic Operations**: MERGE INTO performs inserts, updates, and deletes in a single, ACID-compliant transaction, ensuring data consistency. Separate commands require managing multiple transactions.
- **Faster Writes (Merge-on-Read)**: Using Merge-on-Read, MERGE avoids full-file rewrites. Instead, it writes new data and creates small "delete files" that mark old rows as invalid. This is significantly faster for frequent updates and streaming data.
- **Reduced Write Amplification**: Because only the affected rows or new records are written (instead of rewriting an entire partition or data file), MERGE reduces compute costs and overhead.
- **Optimal CDC Handling**: MERGE INTO is the best way to apply CDC data. It efficiently processes updates, inserts, and deletes simultaneously, especially when paired with v3 deletion vectors. 

== RELEASE NOTES ==

General Changes
* Add support for `WHEN MATCHED THEN DELETE` clause in `MERGE INTO` statements, completing the SQL:2011 MERGE specification. The existing MERGE implementation supported `WHEN MATCHED THEN UPDATE` and `WHEN NOT MATCHED THEN INSERT` but lacked the DELETE case.

Differential Revision: D97683467
apurva-meta added a commit to apurva-meta/presto that referenced this pull request Mar 27, 2026
…restodb#27409)

Summary:
Pull Request resolved: prestodb#27409

Implements the missing WHEN MATCHED THEN DELETE clause for the SQL-standard MERGE INTO statement in Presto. The existing MERGE implementation supports WHEN MATCHED THEN UPDATE and WHEN NOT MATCHED THEN INSERT, but lacked the DELETE case. This completes the SQL:2011 MERGE specification. This is needed for Iceberg support.

Changes across the full stack:
- Grammar (SqlBase.g4): Added mergeDelete alternative to mergeCase rule
- AST (MergeDelete.java): New node extending MergeCase with empty column/expression lists
- Parser (AstBuilder): ANTLR parse tree to MergeDelete AST conversion
- Visitors (AstVisitor, DefaultTraversalVisitor): visitMergeDelete dispatch
- Formatter (SqlFormatter): SQL text generation for WHEN MATCHED THEN DELETE
- Planner (QueryPlanner): MergeDelete maps to DELETE_OPERATION_NUMBER (=2)
- Analyzer (StatementAnalyzer): checkCanDeleteFromTable access control
- Tests (TestSqlParser): Parser round-trip test for MERGE with DELETE clause
- Tests (IcebergDistributedTestBase): 3 integration tests for MERGE DELETE with Iceberg connector

The execution engine (DeleteAndInsertMergeProcessor) and SPI (ConnectorMergeSink) already handle DELETE_OPERATION_NUMBER, so no changes were needed there.

== Key Benefits of MERGE INTO vs. UPDATE/DELETE in Iceberg ==

- **Atomic Operations**: MERGE INTO performs inserts, updates, and deletes in a single, ACID-compliant transaction, ensuring data consistency. Separate commands require managing multiple transactions.
- **Faster Writes (Merge-on-Read)**: Using Merge-on-Read, MERGE avoids full-file rewrites. Instead, it writes new data and creates small "delete files" that mark old rows as invalid. This is significantly faster for frequent updates and streaming data.
- **Reduced Write Amplification**: Because only the affected rows or new records are written (instead of rewriting an entire partition or data file), MERGE reduces compute costs and overhead.
- **Optimal CDC Handling**: MERGE INTO is the best way to apply CDC data. It efficiently processes updates, inserts, and deletes simultaneously, especially when paired with v3 deletion vectors.

== RELEASE NOTES ==

General Changes
* Add support for `WHEN MATCHED THEN DELETE` clause in `MERGE INTO` statements, completing the SQL:2011 MERGE specification. The existing MERGE implementation supported `WHEN MATCHED THEN UPDATE` and `WHEN NOT MATCHED THEN INSERT` but lacked the DELETE case.

Differential Revision: D97683467
@linux-foundation-easycla
Copy link
Copy Markdown

linux-foundation-easycla bot commented Mar 27, 2026

CLA Signed

The committers listed above are authorized under a signed CLA.

  • ✅ login: apurva-meta / name: Apurva Kumar (bb7fb1b)

@steveburnett
Copy link
Copy Markdown
Contributor

  • Please sign the Presto CLA.

xiaoxmeng
xiaoxmeng previously approved these changes Mar 27, 2026
apurva-meta added a commit to apurva-meta/presto that referenced this pull request Mar 27, 2026
…restodb#27409)

Summary:

Implements the missing WHEN MATCHED THEN DELETE clause for the SQL-standard MERGE INTO statement in Presto. The existing MERGE implementation supports WHEN MATCHED THEN UPDATE and WHEN NOT MATCHED THEN INSERT, but lacked the DELETE case. This completes the SQL:2011 MERGE specification. This is needed for Iceberg support.

Changes across the full stack:
- Grammar (SqlBase.g4): Added mergeDelete alternative to mergeCase rule
- AST (MergeDelete.java): New node extending MergeCase with empty column/expression lists
- Parser (AstBuilder): ANTLR parse tree to MergeDelete AST conversion
- Visitors (AstVisitor, DefaultTraversalVisitor): visitMergeDelete dispatch
- Formatter (SqlFormatter): SQL text generation for WHEN MATCHED THEN DELETE
- Planner (QueryPlanner): MergeDelete maps to DELETE_OPERATION_NUMBER (=2)
- Analyzer (StatementAnalyzer): checkCanDeleteFromTable access control
- Tests (TestSqlParser): Parser round-trip test for MERGE with DELETE clause
- Tests (IcebergDistributedTestBase): 3 integration tests for MERGE DELETE with Iceberg connector

The execution engine (DeleteAndInsertMergeProcessor) and SPI (ConnectorMergeSink) already handle DELETE_OPERATION_NUMBER, so no changes were needed there.

== Key Benefits of MERGE INTO vs. UPDATE/DELETE in Iceberg ==

- **Atomic Operations**: MERGE INTO performs inserts, updates, and deletes in a single, ACID-compliant transaction, ensuring data consistency. Separate commands require managing multiple transactions.
- **Faster Writes (Merge-on-Read)**: Using Merge-on-Read, MERGE avoids full-file rewrites. Instead, it writes new data and creates small "delete files" that mark old rows as invalid. This is significantly faster for frequent updates and streaming data.
- **Reduced Write Amplification**: Because only the affected rows or new records are written (instead of rewriting an entire partition or data file), MERGE reduces compute costs and overhead.
- **Optimal CDC Handling**: MERGE INTO is the best way to apply CDC data. It efficiently processes updates, inserts, and deletes simultaneously, especially when paired with v3 deletion vectors. 

== RELEASE NOTES ==

General Changes
* Add support for `WHEN MATCHED THEN DELETE` clause in `MERGE INTO` statements, completing the SQL:2011 MERGE specification. The existing MERGE implementation supported `WHEN MATCHED THEN UPDATE` and `WHEN NOT MATCHED THEN INSERT` but lacked the DELETE case.

Reviewed By: xiaoxmeng

Differential Revision: D97683467
apurva-meta added a commit to apurva-meta/presto that referenced this pull request Mar 27, 2026
…restodb#27409)

Summary:
Pull Request resolved: prestodb#27409

Implements the missing WHEN MATCHED THEN DELETE clause for the SQL-standard MERGE INTO statement in Presto. The existing MERGE implementation supports WHEN MATCHED THEN UPDATE and WHEN NOT MATCHED THEN INSERT, but lacked the DELETE case. This completes the SQL:2011 MERGE specification. This is needed for Iceberg support.

Changes across the full stack:
- Grammar (SqlBase.g4): Added mergeDelete alternative to mergeCase rule
- AST (MergeDelete.java): New node extending MergeCase with empty column/expression lists
- Parser (AstBuilder): ANTLR parse tree to MergeDelete AST conversion
- Visitors (AstVisitor, DefaultTraversalVisitor): visitMergeDelete dispatch
- Formatter (SqlFormatter): SQL text generation for WHEN MATCHED THEN DELETE
- Planner (QueryPlanner): MergeDelete maps to DELETE_OPERATION_NUMBER (=2)
- Analyzer (StatementAnalyzer): checkCanDeleteFromTable access control
- Tests (TestSqlParser): Parser round-trip test for MERGE with DELETE clause
- Tests (IcebergDistributedTestBase): 3 integration tests for MERGE DELETE with Iceberg connector

The execution engine (DeleteAndInsertMergeProcessor) and SPI (ConnectorMergeSink) already handle DELETE_OPERATION_NUMBER, so no changes were needed there.

== Key Benefits of MERGE INTO vs. UPDATE/DELETE in Iceberg ==

- **Atomic Operations**: MERGE INTO performs inserts, updates, and deletes in a single, ACID-compliant transaction, ensuring data consistency. Separate commands require managing multiple transactions.
- **Faster Writes (Merge-on-Read)**: Using Merge-on-Read, MERGE avoids full-file rewrites. Instead, it writes new data and creates small "delete files" that mark old rows as invalid. This is significantly faster for frequent updates and streaming data.
- **Reduced Write Amplification**: Because only the affected rows or new records are written (instead of rewriting an entire partition or data file), MERGE reduces compute costs and overhead.
- **Optimal CDC Handling**: MERGE INTO is the best way to apply CDC data. It efficiently processes updates, inserts, and deletes simultaneously, especially when paired with v3 deletion vectors.

== RELEASE NOTES ==

General Changes
* Add support for `WHEN MATCHED THEN DELETE` clause in `MERGE INTO` statements, completing the SQL:2011 MERGE specification. The existing MERGE implementation supported `WHEN MATCHED THEN UPDATE` and `WHEN NOT MATCHED THEN INSERT` but lacked the DELETE case.

Reviewed By: xiaoxmeng

Differential Revision: D97683467
apurva-meta added a commit to apurva-meta/presto that referenced this pull request Mar 27, 2026
…restodb#27409)

Summary:

Implements the missing WHEN MATCHED THEN DELETE clause for the SQL-standard MERGE INTO statement in Presto. The existing MERGE implementation supports WHEN MATCHED THEN UPDATE and WHEN NOT MATCHED THEN INSERT, but lacked the DELETE case. This completes the SQL:2011 MERGE specification. This is needed for Iceberg support.

Changes across the full stack:
- Grammar (SqlBase.g4): Added mergeDelete alternative to mergeCase rule
- AST (MergeDelete.java): New node extending MergeCase with empty column/expression lists
- Parser (AstBuilder): ANTLR parse tree to MergeDelete AST conversion
- Visitors (AstVisitor, DefaultTraversalVisitor): visitMergeDelete dispatch
- Formatter (SqlFormatter): SQL text generation for WHEN MATCHED THEN DELETE
- Planner (QueryPlanner): MergeDelete maps to DELETE_OPERATION_NUMBER (=2)
- Analyzer (StatementAnalyzer): checkCanDeleteFromTable access control
- Tests (TestSqlParser): Parser round-trip test for MERGE with DELETE clause
- Tests (IcebergDistributedTestBase): 3 integration tests for MERGE DELETE with Iceberg connector

The execution engine (DeleteAndInsertMergeProcessor) and SPI (ConnectorMergeSink) already handle DELETE_OPERATION_NUMBER, so no changes were needed there.

== Key Benefits of MERGE INTO vs. UPDATE/DELETE in Iceberg ==

- **Atomic Operations**: MERGE INTO performs inserts, updates, and deletes in a single, ACID-compliant transaction, ensuring data consistency. Separate commands require managing multiple transactions.
- **Faster Writes (Merge-on-Read)**: Using Merge-on-Read, MERGE avoids full-file rewrites. Instead, it writes new data and creates small "delete files" that mark old rows as invalid. This is significantly faster for frequent updates and streaming data.
- **Reduced Write Amplification**: Because only the affected rows or new records are written (instead of rewriting an entire partition or data file), MERGE reduces compute costs and overhead.
- **Optimal CDC Handling**: MERGE INTO is the best way to apply CDC data. It efficiently processes updates, inserts, and deletes simultaneously, especially when paired with v3 deletion vectors. 


== NO RELEASE NOTE ==

Reviewed By: xiaoxmeng

Differential Revision: D97683467
apurva-meta added a commit to apurva-meta/presto that referenced this pull request Mar 28, 2026
…restodb#27409)

Summary:

Implements the missing WHEN MATCHED THEN DELETE clause for the SQL-standard MERGE INTO statement in Presto. The existing MERGE implementation supports WHEN MATCHED THEN UPDATE and WHEN NOT MATCHED THEN INSERT, but lacked the DELETE case. This completes the SQL:2011 MERGE specification. This is needed for Iceberg support.

Changes across the full stack:
- Grammar (SqlBase.g4): Added mergeDelete alternative to mergeCase rule
- AST (MergeDelete.java): New node extending MergeCase with empty column/expression lists
- Parser (AstBuilder): ANTLR parse tree to MergeDelete AST conversion
- Visitors (AstVisitor, DefaultTraversalVisitor): visitMergeDelete dispatch
- Formatter (SqlFormatter): SQL text generation for WHEN MATCHED THEN DELETE
- Planner (QueryPlanner): MergeDelete maps to DELETE_OPERATION_NUMBER (=2)
- Analyzer (StatementAnalyzer): checkCanDeleteFromTable access control
- Tests (TestSqlParser): Parser round-trip test for MERGE with DELETE clause
- Tests (IcebergDistributedTestBase): 3 integration tests for MERGE DELETE with Iceberg connector

The execution engine (DeleteAndInsertMergeProcessor) and SPI (ConnectorMergeSink) already handle DELETE_OPERATION_NUMBER, so no changes were needed there.

== Key Benefits of MERGE INTO vs. UPDATE/DELETE in Iceberg ==

- **Atomic Operations**: MERGE INTO performs inserts, updates, and deletes in a single, ACID-compliant transaction, ensuring data consistency. Separate commands require managing multiple transactions.
- **Faster Writes (Merge-on-Read)**: Using Merge-on-Read, MERGE avoids full-file rewrites. Instead, it writes new data and creates small "delete files" that mark old rows as invalid. This is significantly faster for frequent updates and streaming data.
- **Reduced Write Amplification**: Because only the affected rows or new records are written (instead of rewriting an entire partition or data file), MERGE reduces compute costs and overhead.
- **Optimal CDC Handling**: MERGE INTO is the best way to apply CDC data. It efficiently processes updates, inserts, and deletes simultaneously, especially when paired with v3 deletion vectors. 


== NO RELEASE NOTE ==

Reviewed By: xiaoxmeng

Differential Revision: D97683467
apurva-meta added a commit to apurva-meta/presto that referenced this pull request Mar 28, 2026
…restodb#27409)

Summary:

Implements the missing WHEN MATCHED THEN DELETE clause for the SQL-standard MERGE INTO statement in Presto. The existing MERGE implementation supports WHEN MATCHED THEN UPDATE and WHEN NOT MATCHED THEN INSERT, but lacked the DELETE case. This completes the SQL:2011 MERGE specification. This is needed for Iceberg support.

Changes across the full stack:
- Grammar (SqlBase.g4): Added mergeDelete alternative to mergeCase rule
- AST (MergeDelete.java): New node extending MergeCase with empty column/expression lists
- Parser (AstBuilder): ANTLR parse tree to MergeDelete AST conversion
- Visitors (AstVisitor, DefaultTraversalVisitor): visitMergeDelete dispatch
- Formatter (SqlFormatter): SQL text generation for WHEN MATCHED THEN DELETE
- Planner (QueryPlanner): MergeDelete maps to DELETE_OPERATION_NUMBER (=2)
- Analyzer (StatementAnalyzer): checkCanDeleteFromTable access control
- Tests (TestSqlParser): Parser round-trip test for MERGE with DELETE clause
- Tests (IcebergDistributedTestBase): 3 integration tests for MERGE DELETE with Iceberg connector

The execution engine (DeleteAndInsertMergeProcessor) and SPI (ConnectorMergeSink) already handle DELETE_OPERATION_NUMBER, so no changes were needed there.

== Key Benefits of MERGE INTO vs. UPDATE/DELETE in Iceberg ==

- **Atomic Operations**: MERGE INTO performs inserts, updates, and deletes in a single, ACID-compliant transaction, ensuring data consistency. Separate commands require managing multiple transactions.
- **Faster Writes (Merge-on-Read)**: Using Merge-on-Read, MERGE avoids full-file rewrites. Instead, it writes new data and creates small "delete files" that mark old rows as invalid. This is significantly faster for frequent updates and streaming data.
- **Reduced Write Amplification**: Because only the affected rows or new records are written (instead of rewriting an entire partition or data file), MERGE reduces compute costs and overhead.
- **Optimal CDC Handling**: MERGE INTO is the best way to apply CDC data. It efficiently processes updates, inserts, and deletes simultaneously, especially when paired with v3 deletion vectors. 


== NO RELEASE NOTE ==

Reviewed By: xiaoxmeng

Differential Revision: D97683467
apurva-meta added a commit to apurva-meta/presto that referenced this pull request Mar 28, 2026
…restodb#27409)

Summary:
Pull Request resolved: prestodb#27409

Implements the missing WHEN MATCHED THEN DELETE clause for the SQL-standard MERGE INTO statement in Presto. The existing MERGE implementation supports WHEN MATCHED THEN UPDATE and WHEN NOT MATCHED THEN INSERT, but lacked the DELETE case. This completes the SQL:2011 MERGE specification. This is needed for Iceberg support.

Changes across the full stack:
- Grammar (SqlBase.g4): Added mergeDelete alternative to mergeCase rule
- AST (MergeDelete.java): New node extending MergeCase with empty column/expression lists
- Parser (AstBuilder): ANTLR parse tree to MergeDelete AST conversion
- Visitors (AstVisitor, DefaultTraversalVisitor): visitMergeDelete dispatch
- Formatter (SqlFormatter): SQL text generation for WHEN MATCHED THEN DELETE
- Planner (QueryPlanner): MergeDelete maps to DELETE_OPERATION_NUMBER (=2)
- Analyzer (StatementAnalyzer): checkCanDeleteFromTable access control
- Tests (TestSqlParser): Parser round-trip test for MERGE with DELETE clause
- Tests (IcebergDistributedTestBase): 3 integration tests for MERGE DELETE with Iceberg connector

The execution engine (DeleteAndInsertMergeProcessor) and SPI (ConnectorMergeSink) already handle DELETE_OPERATION_NUMBER, so no changes were needed there.

== Key Benefits of MERGE INTO vs. UPDATE/DELETE in Iceberg ==

- **Atomic Operations**: MERGE INTO performs inserts, updates, and deletes in a single, ACID-compliant transaction, ensuring data consistency. Separate commands require managing multiple transactions.
- **Faster Writes (Merge-on-Read)**: Using Merge-on-Read, MERGE avoids full-file rewrites. Instead, it writes new data and creates small "delete files" that mark old rows as invalid. This is significantly faster for frequent updates and streaming data.
- **Reduced Write Amplification**: Because only the affected rows or new records are written (instead of rewriting an entire partition or data file), MERGE reduces compute costs and overhead.
- **Optimal CDC Handling**: MERGE INTO is the best way to apply CDC data. It efficiently processes updates, inserts, and deletes simultaneously, especially when paired with v3 deletion vectors.

== NO RELEASE NOTE ==

Reviewed By: xiaoxmeng

Differential Revision: D97683467
apurva-meta added a commit to apurva-meta/presto that referenced this pull request Mar 28, 2026
…restodb#27409)

Summary:

Implements the missing WHEN MATCHED THEN DELETE clause for the SQL-standard MERGE INTO statement in Presto. The existing MERGE implementation supports WHEN MATCHED THEN UPDATE and WHEN NOT MATCHED THEN INSERT, but lacked the DELETE case. This completes the SQL:2011 MERGE specification. This is needed for Iceberg support.

Changes across the full stack:
- Grammar (SqlBase.g4): Added mergeDelete alternative to mergeCase rule
- AST (MergeDelete.java): New node extending MergeCase with empty column/expression lists
- Parser (AstBuilder): ANTLR parse tree to MergeDelete AST conversion
- Visitors (AstVisitor, DefaultTraversalVisitor): visitMergeDelete dispatch
- Formatter (SqlFormatter): SQL text generation for WHEN MATCHED THEN DELETE
- Planner (QueryPlanner): MergeDelete maps to DELETE_OPERATION_NUMBER (=2)
- Analyzer (StatementAnalyzer): checkCanDeleteFromTable access control
- Tests (TestSqlParser): Parser round-trip test for MERGE with DELETE clause
- Tests (IcebergDistributedTestBase): 3 integration tests for MERGE DELETE with Iceberg connector

The execution engine (DeleteAndInsertMergeProcessor) and SPI (ConnectorMergeSink) already handle DELETE_OPERATION_NUMBER, so no changes were needed there.

== Key Benefits of MERGE INTO vs. UPDATE/DELETE in Iceberg ==

- **Atomic Operations**: MERGE INTO performs inserts, updates, and deletes in a single, ACID-compliant transaction, ensuring data consistency. Separate commands require managing multiple transactions.
- **Faster Writes (Merge-on-Read)**: Using Merge-on-Read, MERGE avoids full-file rewrites. Instead, it writes new data and creates small "delete files" that mark old rows as invalid. This is significantly faster for frequent updates and streaming data.
- **Reduced Write Amplification**: Because only the affected rows or new records are written (instead of rewriting an entire partition or data file), MERGE reduces compute costs and overhead.
- **Optimal CDC Handling**: MERGE INTO is the best way to apply CDC data. It efficiently processes updates, inserts, and deletes simultaneously, especially when paired with v3 deletion vectors. 


== NO RELEASE NOTE ==

Reviewed By: xiaoxmeng

Differential Revision: D97683467
Copy link
Copy Markdown
Member

@hantangwangd hantangwangd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @apurva-meta for adding this feature, overall looks good to me! Would you mind adding documentation on WHEN MATCHED THEN DELETE to mrege.rst?

Also, is the change for Support SQL-standard time travel syntax related in this PR? Would it be OK to move it to a separate PR?

@meta-codesync meta-codesync bot changed the title feat: Add WHEN MATCHED THEN DELETE support to MERGE INTO statement (#27409) feat: Add WHEN MATCHED THEN DELETE support to MERGE INTO statement Mar 30, 2026
@apurva-meta
Copy link
Copy Markdown
Contributor Author

Thanks @apurva-meta for adding this feature, overall looks good to me! Would you mind adding documentation on WHEN MATCHED THEN DELETE to mrege.rst?

Also, is the change for Support SQL-standard time travel syntax related in this PR? Would it be OK to move it to a separate PR?

Thanks @hantangwangd for the review. I have documented the MERGE INTO..DELETE in the merge.rst file. Also removed the time travel commit from this PR. Please have a look.

Copy link
Copy Markdown
Contributor

@steveburnett steveburnett left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! (docs)

Pull branch, local doc build, looks good. Thank you!

@meta-codesync meta-codesync bot changed the title feat: Add WHEN MATCHED THEN DELETE support to MERGE INTO statement feat: Add WHEN MATCHED THEN DELETE support to MERGE INTO statement (#27409) Mar 30, 2026
apurva-meta added a commit to apurva-meta/presto that referenced this pull request Mar 30, 2026
…restodb#27409)

Summary:

Implements the missing WHEN MATCHED THEN DELETE clause for the SQL-standard MERGE INTO statement in Presto. The existing MERGE implementation supports WHEN MATCHED THEN UPDATE and WHEN NOT MATCHED THEN INSERT, but lacked the DELETE case. This completes the SQL:2011 MERGE specification.

Changes across the full stack:
- Grammar (SqlBase.g4): Added mergeDelete alternative to mergeCase rule
- AST (MergeDelete.java): New node extending MergeCase with empty column/expression lists
- Parser (AstBuilder): ANTLR parse tree to MergeDelete AST conversion
- Visitors (AstVisitor, DefaultTraversalVisitor): visitMergeDelete dispatch
- Formatter (SqlFormatter): SQL text generation for WHEN MATCHED THEN DELETE
- Planner (QueryPlanner): MergeDelete maps to DELETE_OPERATION_NUMBER (=2)
- Analyzer (StatementAnalyzer): checkCanDeleteFromTable access control
- Tests (TestSqlParser): Parser round-trip test for MERGE with DELETE clause
- Tests (IcebergDistributedTestBase): 3 integration tests for MERGE DELETE with Iceberg connector

The execution engine (DeleteAndInsertMergeProcessor) and SPI (ConnectorMergeSink) already handle DELETE_OPERATION_NUMBER, so no changes were needed there.

== RELEASE NOTES ==

General Changes
* Add support for `WHEN MATCHED THEN DELETE` clause in `MERGE INTO` statements, completing the SQL:2011 MERGE specification. The existing MERGE implementation supported `WHEN MATCHED THEN UPDATE` and `WHEN NOT MATCHED THEN INSERT` but lacked the DELETE case.

Reviewed By: xiaoxmeng

Differential Revision: D97683467
…restodb#27409)

Summary:

Implements the missing WHEN MATCHED THEN DELETE clause for the SQL-standard MERGE INTO statement in Presto. The existing MERGE implementation supports WHEN MATCHED THEN UPDATE and WHEN NOT MATCHED THEN INSERT, but lacked the DELETE case. This completes the SQL:2011 MERGE specification.

Changes across the full stack:
- Grammar (SqlBase.g4): Added mergeDelete alternative to mergeCase rule
- AST (MergeDelete.java): New node extending MergeCase with empty column/expression lists
- Parser (AstBuilder): ANTLR parse tree to MergeDelete AST conversion
- Visitors (AstVisitor, DefaultTraversalVisitor): visitMergeDelete dispatch
- Formatter (SqlFormatter): SQL text generation for WHEN MATCHED THEN DELETE
- Planner (QueryPlanner): MergeDelete maps to DELETE_OPERATION_NUMBER (=2)
- Analyzer (StatementAnalyzer): checkCanDeleteFromTable access control
- Tests (TestSqlParser): Parser round-trip test for MERGE with DELETE clause
- Tests (IcebergDistributedTestBase): 3 integration tests for MERGE DELETE with Iceberg connector

The execution engine (DeleteAndInsertMergeProcessor) and SPI (ConnectorMergeSink) already handle DELETE_OPERATION_NUMBER, so no changes were needed there.

== RELEASE NOTES ==

General Changes
* Add support for `WHEN MATCHED THEN DELETE` clause in `MERGE INTO` statements, completing the SQL:2011 MERGE specification. The existing MERGE implementation supported `WHEN MATCHED THEN UPDATE` and `WHEN NOT MATCHED THEN INSERT` but lacked the DELETE case.

Reviewed By: xiaoxmeng

Differential Revision: D97683467
Copy link
Copy Markdown
Member

@hantangwangd hantangwangd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @apurva-meta, lgtm!

@hantangwangd hantangwangd merged commit 57025b1 into prestodb:master Mar 31, 2026
87 of 90 checks passed
bibith4 pushed a commit to bibith4/presto that referenced this pull request Apr 1, 2026
…restodb#27409) (prestodb#27409)

Summary:

Implements the missing WHEN MATCHED THEN DELETE clause for the
SQL-standard MERGE INTO statement in Presto. The existing MERGE
implementation supports WHEN MATCHED THEN UPDATE and WHEN NOT MATCHED
THEN INSERT, but lacked the DELETE case. This completes the SQL:2011
MERGE specification.

Changes across the full stack:
- Grammar (SqlBase.g4): Added mergeDelete alternative to mergeCase rule
- AST (MergeDelete.java): New node extending MergeCase with empty
column/expression lists
- Parser (AstBuilder): ANTLR parse tree to MergeDelete AST conversion
- Visitors (AstVisitor, DefaultTraversalVisitor): visitMergeDelete
dispatch
- Formatter (SqlFormatter): SQL text generation for WHEN MATCHED THEN
DELETE
- Planner (QueryPlanner): MergeDelete maps to DELETE_OPERATION_NUMBER
(=2)
- Analyzer (StatementAnalyzer): checkCanDeleteFromTable access control
- Tests (TestSqlParser): Parser round-trip test for MERGE with DELETE
clause
- Tests (IcebergDistributedTestBase): 3 integration tests for MERGE
DELETE with Iceberg connector

The execution engine (DeleteAndInsertMergeProcessor) and SPI
(ConnectorMergeSink) already handle DELETE_OPERATION_NUMBER, so no
changes were needed there.

== RELEASE NOTES ==

General Changes
* Add support for `WHEN MATCHED THEN DELETE` clause in `MERGE INTO`
statements, completing the SQL:2011 MERGE specification. The existing
MERGE implementation supported `WHEN MATCHED THEN UPDATE` and `WHEN NOT
MATCHED THEN INSERT` but lacked the DELETE case.

Reviewed By: xiaoxmeng

Differential Revision: D97683467
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants