This is an automated email from the ASF dual-hosted git repository.

morrysnow pushed a commit to branch branch-3.1
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/branch-3.1 by this push:
     new 0c9a36eb8b3 branch-3.1: [opt](iceberg)support drop tag and branch 
#52453 (#52961)
0c9a36eb8b3 is described below

commit 0c9a36eb8b39da8f951c5efb0a72135c1bfd6b9e
Author: Mingyu Chen (Rayner) <[email protected]>
AuthorDate: Tue Jul 8 19:45:32 2025 -0700

    branch-3.1: [opt](iceberg)support drop tag and branch #52453 (#52961)
    
    bp #52453
    
    Co-authored-by: wuwenchi <[email protected]>
    Co-authored-by: wuwenchi.wwc <[email protected]>
---
 .../antlr4/org/apache/doris/nereids/DorisParser.g4 |  10 ++
 fe/fe-core/src/main/cup/sql_parser.cup             |  16 +++-
 .../main/java/org/apache/doris/alter/Alter.java    |  10 ++
 .../org/apache/doris/analysis/AlterTableStmt.java  |   4 +-
 .../apache/doris/analysis/DropBranchClause.java    |  55 +++++++++++
 .../org/apache/doris/analysis/DropTagClause.java   |  55 +++++++++++
 .../org/apache/doris/datasource/CatalogIf.java     |  12 ++-
 .../apache/doris/datasource/ExternalCatalog.java   |  40 +++++++-
 .../doris/datasource/hive/HiveMetadataOps.java     |  12 +++
 .../datasource/iceberg/IcebergMetadataOps.java     |  43 ++++++++-
 .../datasource/operations/ExternalMetadataOps.java |  40 +++++++-
 .../trees/plans/commands/info/DropBranchInfo.java  |  56 +++++++++++
 .../trees/plans/commands/info/DropTagInfo.java     |  56 +++++++++++
 .../java/org/apache/doris/persist/EditLog.java     |   2 +-
 .../IcebergExternalTableBranchAndTagTest.java      | 103 ++++++++++++++++++++-
 .../commands/info/DropBranchOrTagInfoTest.java     |  52 +++++++++++
 .../iceberg/iceberg_branch_tag_operate.groovy      |  60 ++++++++++++
 17 files changed, 614 insertions(+), 12 deletions(-)

diff --git a/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4 
b/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4
index fb53ae82c80..5cc7eef804f 100644
--- a/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4
+++ b/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4
@@ -642,6 +642,8 @@ alterTableClause
         INTERVAL INTEGER_VALUE unit=identifier? properties=propertyClause?     
     #alterMultiPartitionClause
     | createOrReplaceTagClause                                                 
     #createOrReplaceTagClauses
     | createOrReplaceBranchClause                                              
     #createOrReplaceBranchClauses
+    | dropBranchClause                                                         
     #dropBranchClauses
+    | dropTagClause                                                            
     #dropTagClauses
     ;
 
 createOrReplaceTagClause
@@ -680,6 +682,14 @@ timeValueWithUnit
     : timeValue=INTEGER_VALUE  timeUnit=(DAYS | HOURS | MINUTES)
     ;
 
+dropBranchClause
+    : DROP BRANCH (IF EXISTS)? name=identifier
+    ;
+
+dropTagClause
+    : DROP TAG (IF EXISTS)? name=identifier
+    ;
+
 columnPosition
     : FIRST
     | AFTER position=identifier
diff --git a/fe/fe-core/src/main/cup/sql_parser.cup 
b/fe/fe-core/src/main/cup/sql_parser.cup
index 95d77384a81..e2f77ba262f 100644
--- a/fe/fe-core/src/main/cup/sql_parser.cup
+++ b/fe/fe-core/src/main/cup/sql_parser.cup
@@ -59,11 +59,13 @@ import org.apache.doris.cloud.analysis.UseCloudClusterStmt;
 import org.apache.doris.cloud.proto.Cloud.StagePB;
 import org.apache.doris.indexpolicy.IndexPolicyTypeEnum;
 import org.apache.doris.mysql.MysqlPassword;
+import org.apache.doris.nereids.trees.plans.commands.info.BranchOptions;
 import 
org.apache.doris.nereids.trees.plans.commands.info.CreateOrReplaceBranchInfo;
 import 
org.apache.doris.nereids.trees.plans.commands.info.CreateOrReplaceTagInfo;
-import org.apache.doris.nereids.trees.plans.commands.info.BranchOptions;
-import org.apache.doris.nereids.trees.plans.commands.info.TagOptions;
+import org.apache.doris.nereids.trees.plans.commands.info.DropBranchInfo;
+import org.apache.doris.nereids.trees.plans.commands.info.DropTagInfo;
 import org.apache.doris.nereids.trees.plans.commands.info.RetentionSnapshots;
+import org.apache.doris.nereids.trees.plans.commands.info.TagOptions;
 import org.apache.doris.load.loadv2.LoadTask;
 import org.apache.doris.policy.PolicyTypeEnum;
 import org.apache.doris.resource.workloadschedpolicy.WorkloadConditionMeta;
@@ -1812,6 +1814,16 @@ alter_table_clause ::=
         CreateOrReplaceTagInfo tagInfo = new CreateOrReplaceTagInfo(tagName, 
true, true, false, tagOptions);
         RESULT = new CreateOrReplaceTagClause(tagInfo);
     :}
+    | KW_DROP KW_BRANCH opt_if_exists:ifExists ident:branchName
+    {:
+        DropBranchInfo branchInfo = new DropBranchInfo(branchName, ifExists);
+        RESULT = new DropBranchClause(branchInfo);
+    :}
+    | KW_DROP KW_TAG opt_if_exists:ifExists ident:tagName
+    {:
+        DropTagInfo tagInfo = new DropTagInfo(tagName, ifExists);
+        RESULT = new DropTagClause(tagInfo);
+    :}
     ;
 
 branch_options ::=
diff --git a/fe/fe-core/src/main/java/org/apache/doris/alter/Alter.java 
b/fe/fe-core/src/main/java/org/apache/doris/alter/Alter.java
index d0b3909ae11..5f96d823315 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/alter/Alter.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/alter/Alter.java
@@ -28,9 +28,11 @@ import org.apache.doris.analysis.ColumnRenameClause;
 import org.apache.doris.analysis.CreateMaterializedViewStmt;
 import org.apache.doris.analysis.CreateOrReplaceBranchClause;
 import org.apache.doris.analysis.CreateOrReplaceTagClause;
+import org.apache.doris.analysis.DropBranchClause;
 import org.apache.doris.analysis.DropMaterializedViewStmt;
 import org.apache.doris.analysis.DropPartitionClause;
 import org.apache.doris.analysis.DropPartitionFromIndexClause;
+import org.apache.doris.analysis.DropTagClause;
 import org.apache.doris.analysis.ModifyColumnCommentClause;
 import org.apache.doris.analysis.ModifyDistributionClause;
 import org.apache.doris.analysis.ModifyEngineClause;
@@ -350,6 +352,14 @@ public class Alter {
                 table.getCatalog().createOrReplaceTag(
                         table.getDbName(), table.getName(),
                         ((CreateOrReplaceTagClause) alterClause).getTagInfo());
+            } else if (alterClause instanceof DropBranchClause) {
+                table.getCatalog().dropBranch(
+                        table.getDbName(), table.getName(),
+                        ((DropBranchClause) alterClause).getDropBranchInfo());
+            } else if (alterClause instanceof DropTagClause) {
+                table.getCatalog().dropTag(
+                        table.getDbName(), table.getName(),
+                        ((DropTagClause) alterClause).getDropTagInfo());
             } else {
                 throw new UserException("Invalid alter operations for external 
table: " + alterClauses);
             }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/analysis/AlterTableStmt.java 
b/fe/fe-core/src/main/java/org/apache/doris/analysis/AlterTableStmt.java
index 63533a4f6f2..36db1e3d863 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/analysis/AlterTableStmt.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/AlterTableStmt.java
@@ -188,7 +188,9 @@ public class AlterTableStmt extends DdlStmt implements 
NotFallbackInParser {
                     || alterClause instanceof ReorderColumnsClause
                     || alterClause instanceof ModifyEngineClause
                     || alterClause instanceof CreateOrReplaceBranchClause
-                    || alterClause instanceof CreateOrReplaceTagClause) {
+                    || alterClause instanceof CreateOrReplaceTagClause
+                    || alterClause instanceof DropBranchClause
+                    || alterClause instanceof DropTagClause) {
                 clauses.add(alterClause);
             } else {
                 throw new AnalysisException(table.getType().toString() + " [" 
+ table.getName() + "] "
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/analysis/DropBranchClause.java 
b/fe/fe-core/src/main/java/org/apache/doris/analysis/DropBranchClause.java
new file mode 100644
index 00000000000..d5ea0a12b03
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/DropBranchClause.java
@@ -0,0 +1,55 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.analysis;
+
+import org.apache.doris.alter.AlterOpType;
+import org.apache.doris.common.UserException;
+import org.apache.doris.nereids.trees.plans.commands.info.DropBranchInfo;
+
+public class DropBranchClause extends AlterTableClause {
+    private final DropBranchInfo dropBranchInfo;
+
+    public DropBranchClause(DropBranchInfo dropBranchInfo) {
+        super(AlterOpType.ALTER_BRANCH);
+        this.dropBranchInfo = dropBranchInfo;
+    }
+
+    @Override
+    public boolean allowOpMTMV() {
+        return false;
+    }
+
+    @Override
+    public boolean needChangeMTMVState() {
+        return false;
+    }
+
+    @Override
+    public void analyze(Analyzer analyzer) throws UserException {
+
+    }
+
+    @Override
+    public String toSql() {
+        return dropBranchInfo.toSql();
+    }
+
+    public DropBranchInfo getDropBranchInfo() {
+        return dropBranchInfo;
+    }
+}
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/analysis/DropTagClause.java 
b/fe/fe-core/src/main/java/org/apache/doris/analysis/DropTagClause.java
new file mode 100644
index 00000000000..5ecf53987ca
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/DropTagClause.java
@@ -0,0 +1,55 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.analysis;
+
+import org.apache.doris.alter.AlterOpType;
+import org.apache.doris.common.UserException;
+import org.apache.doris.nereids.trees.plans.commands.info.DropTagInfo;
+
+public class DropTagClause extends AlterTableClause {
+    private final DropTagInfo dropTagInfo;
+
+    public DropTagClause(DropTagInfo dropTagInfo) {
+        super(AlterOpType.ALTER_TAG);
+        this.dropTagInfo = dropTagInfo;
+    }
+
+    @Override
+    public boolean allowOpMTMV() {
+        return false;
+    }
+
+    @Override
+    public boolean needChangeMTMVState() {
+        return false;
+    }
+
+    @Override
+    public void analyze(Analyzer analyzer) throws UserException {
+
+    }
+
+    @Override
+    public String toSql() {
+        return dropTagInfo.toSql();
+    }
+
+    public DropTagInfo getDropTagInfo() {
+        return dropTagInfo;
+    }
+}
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/datasource/CatalogIf.java 
b/fe/fe-core/src/main/java/org/apache/doris/datasource/CatalogIf.java
index 1a3e0a0073e..3355470d95e 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/datasource/CatalogIf.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/datasource/CatalogIf.java
@@ -33,6 +33,8 @@ import org.apache.doris.common.MetaNotFoundException;
 import org.apache.doris.common.UserException;
 import 
org.apache.doris.nereids.trees.plans.commands.info.CreateOrReplaceBranchInfo;
 import 
org.apache.doris.nereids.trees.plans.commands.info.CreateOrReplaceTagInfo;
+import org.apache.doris.nereids.trees.plans.commands.info.DropBranchInfo;
+import org.apache.doris.nereids.trees.plans.commands.info.DropTagInfo;
 
 import com.google.common.base.Strings;
 import com.google.common.collect.Lists;
@@ -221,7 +223,15 @@ public interface CatalogIf<T extends DatabaseIf> {
         throw new UserException("Not support create or replace tag operation");
     }
 
-    default void replayCreateOrReplaceBranchOrTag(String dbName, String 
tblName) {
+    default void replayOperateOnBranchOrTag(String dbName, String tblName) {
 
     }
+
+    default void dropBranch(String db, String tbl, DropBranchInfo branchInfo) 
throws UserException {
+        throw new UserException("Not support drop branch operation");
+    }
+
+    default void dropTag(String db, String tbl, DropTagInfo tagInfo) throws 
UserException {
+        throw new UserException("Not support drop tag operation");
+    }
 }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/datasource/ExternalCatalog.java 
b/fe/fe-core/src/main/java/org/apache/doris/datasource/ExternalCatalog.java
index d360c7089fb..09a0e67f5ec 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/datasource/ExternalCatalog.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/datasource/ExternalCatalog.java
@@ -62,6 +62,8 @@ import 
org.apache.doris.datasource.trinoconnector.TrinoConnectorExternalDatabase
 import org.apache.doris.fs.remote.dfs.DFSFileSystem;
 import 
org.apache.doris.nereids.trees.plans.commands.info.CreateOrReplaceBranchInfo;
 import 
org.apache.doris.nereids.trees.plans.commands.info.CreateOrReplaceTagInfo;
+import org.apache.doris.nereids.trees.plans.commands.info.DropBranchInfo;
+import org.apache.doris.nereids.trees.plans.commands.info.DropTagInfo;
 import org.apache.doris.persist.CreateDbInfo;
 import org.apache.doris.persist.CreateTableInfo;
 import org.apache.doris.persist.DropDbInfo;
@@ -1333,9 +1335,43 @@ public abstract class ExternalCatalog
     }
 
     @Override
-    public void replayCreateOrReplaceBranchOrTag(String dbName, String 
tblName) {
+    public void replayOperateOnBranchOrTag(String dbName, String tblName) {
         if (metadataOps != null) {
-            metadataOps.afterCreateOrReplaceBranchOrTag(dbName, tblName);
+            metadataOps.afterOperateOnBranchOrTag(dbName, tblName);
+        }
+    }
+
+    @Override
+    public void dropBranch(String db, String tbl, DropBranchInfo branchInfo) 
throws UserException {
+        makeSureInitialized();
+        if (metadataOps == null) {
+            throw new DdlException("DropBranch operation is not supported for 
catalog: " + getName());
+        }
+        try {
+            metadataOps.dropBranch(db, tbl, branchInfo);
+            TableBranchOrTagInfo info = new TableBranchOrTagInfo(getName(), 
db, tbl);
+            Env.getCurrentEnv().getEditLog().logBranchOrTag(info);
+        } catch (Exception e) {
+            LOG.warn("Failed to drop branch for table {}.{} in catalog {}",
+                    db, tbl, getName(), e);
+            throw e;
+        }
+    }
+
+    @Override
+    public void dropTag(String db, String tbl, DropTagInfo tagInfo) throws 
UserException {
+        makeSureInitialized();
+        if (metadataOps == null) {
+            throw new DdlException("DropTag operation is not supported for 
catalog: " + getName());
+        }
+        try {
+            metadataOps.dropTag(db, tbl, tagInfo);
+            TableBranchOrTagInfo info = new TableBranchOrTagInfo(getName(), 
db, tbl);
+            Env.getCurrentEnv().getEditLog().logBranchOrTag(info);
+        } catch (Exception e) {
+            LOG.warn("Failed to drop tag for table {}.{} in catalog {}",
+                    db, tbl, getName(), e);
+            throw e;
         }
     }
 }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/datasource/hive/HiveMetadataOps.java
 
b/fe/fe-core/src/main/java/org/apache/doris/datasource/hive/HiveMetadataOps.java
index aa88fb8abf3..c042f5ec25a 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/datasource/hive/HiveMetadataOps.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/datasource/hive/HiveMetadataOps.java
@@ -42,6 +42,8 @@ import 
org.apache.doris.datasource.operations.ExternalMetadataOps;
 import org.apache.doris.datasource.property.constants.HMSProperties;
 import 
org.apache.doris.nereids.trees.plans.commands.info.CreateOrReplaceBranchInfo;
 import 
org.apache.doris.nereids.trees.plans.commands.info.CreateOrReplaceTagInfo;
+import org.apache.doris.nereids.trees.plans.commands.info.DropBranchInfo;
+import org.apache.doris.nereids.trees.plans.commands.info.DropTagInfo;
 import org.apache.doris.qe.ConnectContext;
 
 import com.google.common.annotations.VisibleForTesting;
@@ -379,6 +381,16 @@ public class HiveMetadataOps implements 
ExternalMetadataOps {
         throw new UserException("Not support create or replace tag in hive 
catalog.");
     }
 
+    @Override
+    public void dropTagImpl(String dbName, String tblName, DropTagInfo 
tagInfo) throws UserException {
+        throw new UserException("Not support drop tag in hive catalog.");
+    }
+
+    @Override
+    public void dropBranchImpl(String dbName, String tblName, DropBranchInfo 
branchInfo) throws UserException {
+        throw new UserException("Not support drop branch in hive catalog.");
+    }
+
     @Override
     public List<String> listTableNames(String dbName) {
         return client.getAllTables(dbName);
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/datasource/iceberg/IcebergMetadataOps.java
 
b/fe/fe-core/src/main/java/org/apache/doris/datasource/iceberg/IcebergMetadataOps.java
index 6ff4df612af..2c3d7290e06 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/datasource/iceberg/IcebergMetadataOps.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/datasource/iceberg/IcebergMetadataOps.java
@@ -38,12 +38,15 @@ import 
org.apache.doris.datasource.operations.ExternalMetadataOps;
 import org.apache.doris.nereids.trees.plans.commands.info.BranchOptions;
 import 
org.apache.doris.nereids.trees.plans.commands.info.CreateOrReplaceBranchInfo;
 import 
org.apache.doris.nereids.trees.plans.commands.info.CreateOrReplaceTagInfo;
+import org.apache.doris.nereids.trees.plans.commands.info.DropBranchInfo;
+import org.apache.doris.nereids.trees.plans.commands.info.DropTagInfo;
 import org.apache.doris.nereids.trees.plans.commands.info.TagOptions;
 
 import org.apache.iceberg.ManageSnapshots;
 import org.apache.iceberg.PartitionSpec;
 import org.apache.iceberg.Schema;
 import org.apache.iceberg.Snapshot;
+import org.apache.iceberg.SnapshotRef;
 import org.apache.iceberg.Table;
 import org.apache.iceberg.catalog.Catalog;
 import org.apache.iceberg.catalog.Namespace;
@@ -401,7 +404,7 @@ public class IcebergMetadataOps implements 
ExternalMetadataOps {
     }
 
     @Override
-    public void afterCreateOrReplaceBranchOrTag(String dbName, String tblName) 
{
+    public void afterOperateOnBranchOrTag(String dbName, String tblName) {
         ExternalDatabase<?> db = dorisCatalog.getDbNullable(dbName);
         if (db != null) {
             ExternalTable tbl = db.getTableNullable(tblName);
@@ -455,6 +458,44 @@ public class IcebergMetadataOps implements 
ExternalMetadataOps {
         }
     }
 
+    @Override
+    public void dropTagImpl(String dbName, String tblName, DropTagInfo 
tagInfo) throws UserException {
+        String tagName = tagInfo.getTagName();
+        boolean ifExists = tagInfo.getIfExists();
+        Table icebergTable = IcebergUtils.getIcebergTable(dorisCatalog, 
dbName, tblName);
+        SnapshotRef snapshotRef = icebergTable.refs().get(tagName);
+
+        if (snapshotRef != null || !ifExists) {
+            ManageSnapshots manageSnapshots = icebergTable.manageSnapshots();
+            try {
+                preExecutionAuthenticator.execute(() -> 
manageSnapshots.removeTag(tagName).commit());
+            } catch (Exception e) {
+                throw new RuntimeException(
+                        "Failed to drop tag: " + tagName + " in table: " + 
icebergTable.name()
+                        + ", error message is: " + e.getMessage(), e);
+            }
+        }
+    }
+
+    @Override
+    public void dropBranchImpl(String dbName, String tblName, DropBranchInfo 
branchInfo) throws UserException {
+        String branchName = branchInfo.getBranchName();
+        boolean ifExists = branchInfo.getIfExists();
+        Table icebergTable = IcebergUtils.getIcebergTable(dorisCatalog, 
dbName, tblName);
+        SnapshotRef snapshotRef = icebergTable.refs().get(branchName);
+
+        if (snapshotRef != null || !ifExists) {
+            ManageSnapshots manageSnapshots = icebergTable.manageSnapshots();
+            try {
+                preExecutionAuthenticator.execute(() -> 
manageSnapshots.removeBranch(branchName).commit());
+            } catch (Exception e) {
+                throw new RuntimeException(
+                        "Failed to drop branch: " + branchName + " in table: " 
+ icebergTable.name()
+                        + ", error message is: " + e.getMessage(), e);
+            }
+        }
+    }
+
     public PreExecutionAuthenticator getPreExecutionAuthenticator() {
         return preExecutionAuthenticator;
     }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/datasource/operations/ExternalMetadataOps.java
 
b/fe/fe-core/src/main/java/org/apache/doris/datasource/operations/ExternalMetadataOps.java
index d790a8cd085..450a49e3e17 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/datasource/operations/ExternalMetadataOps.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/datasource/operations/ExternalMetadataOps.java
@@ -25,6 +25,8 @@ import org.apache.doris.common.DdlException;
 import org.apache.doris.common.UserException;
 import 
org.apache.doris.nereids.trees.plans.commands.info.CreateOrReplaceBranchInfo;
 import 
org.apache.doris.nereids.trees.plans.commands.info.CreateOrReplaceTagInfo;
+import org.apache.doris.nereids.trees.plans.commands.info.DropBranchInfo;
+import org.apache.doris.nereids.trees.plans.commands.info.DropTagInfo;
 
 import org.apache.iceberg.view.View;
 
@@ -127,13 +129,13 @@ public interface ExternalMetadataOps {
     default void createOrReplaceBranch(String dbName, String tblName, 
CreateOrReplaceBranchInfo branchInfo)
             throws UserException {
         createOrReplaceBranchImpl(dbName, tblName, branchInfo);
-        afterCreateOrReplaceBranchOrTag(dbName, tblName);
+        afterOperateOnBranchOrTag(dbName, tblName);
     }
 
     void createOrReplaceBranchImpl(String dbName, String tblName, 
CreateOrReplaceBranchInfo branchInfo)
             throws UserException;
 
-    default void afterCreateOrReplaceBranchOrTag(String dbName, String 
tblName) {
+    default void afterOperateOnBranchOrTag(String dbName, String tblName) {
     }
 
     /**
@@ -147,12 +149,44 @@ public interface ExternalMetadataOps {
     default void createOrReplaceTag(String dbName, String tblName, 
CreateOrReplaceTagInfo tagInfo)
             throws UserException {
         createOrReplaceTagImpl(dbName, tblName, tagInfo);
-        afterCreateOrReplaceBranchOrTag(dbName, tblName);
+        afterOperateOnBranchOrTag(dbName, tblName);
     }
 
     void createOrReplaceTagImpl(String dbName, String tblName, 
CreateOrReplaceTagInfo tagInfo)
             throws UserException;
 
+    /**
+     * drop tag in external metastore
+     *
+     * @param dbName
+     * @param tblName
+     * @param tagInfo
+     * @throws UserException
+     */
+    default void dropTag(String dbName, String tblName, DropTagInfo tagInfo)
+            throws UserException {
+        dropTagImpl(dbName, tblName, tagInfo);
+        afterOperateOnBranchOrTag(dbName, tblName);
+    }
+
+    void dropTagImpl(String dbName, String tblName, DropTagInfo tagInfo) 
throws UserException;
+
+    /**
+     * drop branch in external metastore
+     *
+     * @param dbName
+     * @param tblName
+     * @param branchInfo
+     * @throws UserException
+     */
+    default void dropBranch(String dbName, String tblName, DropBranchInfo 
branchInfo)
+            throws UserException {
+        dropBranchImpl(dbName, tblName, branchInfo);
+        afterOperateOnBranchOrTag(dbName, tblName);
+    }
+
+    void dropBranchImpl(String dbName, String tblName, DropBranchInfo 
branchInfo) throws UserException;
+
     /**
      *
      * @return
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/DropBranchInfo.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/DropBranchInfo.java
new file mode 100644
index 00000000000..6b019740074
--- /dev/null
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/DropBranchInfo.java
@@ -0,0 +1,56 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.trees.plans.commands.info;
+
+/**
+ * Represents the information needed to drop a branch in the system.
+ *
+ */
+public class DropBranchInfo {
+
+    private final String branchName;
+    private final Boolean ifExists;
+
+    public DropBranchInfo(String branchName, boolean ifExists) {
+        this.branchName = branchName;
+        this.ifExists = ifExists;
+    }
+
+    public String getBranchName() {
+        return branchName;
+    }
+
+    public Boolean getIfExists() {
+        return ifExists;
+    }
+
+    /**
+     * Generates the SQL representation of the drop branch command.
+     *
+     * @return SQL string for drop a branch
+     */
+    public String toSql() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("DROP BRANCH");
+        if (ifExists) {
+            sb.append(" IF EXISTS");
+        }
+        sb.append(" ").append(branchName);
+        return sb.toString();
+    }
+}
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/DropTagInfo.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/DropTagInfo.java
new file mode 100644
index 00000000000..f53d902549c
--- /dev/null
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/DropTagInfo.java
@@ -0,0 +1,56 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.trees.plans.commands.info;
+
+/**
+ * Represents the information needed to drop a tag in the system.
+ *
+ */
+public class DropTagInfo {
+
+    private final String tagName;
+    private final Boolean ifExists;
+
+    public DropTagInfo(String tagName, boolean ifExists) {
+        this.tagName = tagName;
+        this.ifExists = ifExists;
+    }
+
+    public String getTagName() {
+        return tagName;
+    }
+
+    public Boolean getIfExists() {
+        return ifExists;
+    }
+
+    /**
+     * Generates the SQL representation of the drop tag command.
+     *
+     * @return SQL string for drop a tag
+     */
+    public String toSql() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("DROP TAG");
+        if (ifExists) {
+            sb.append(" IF EXISTS");
+        }
+        sb.append(" ").append(tagName);
+        return sb.toString();
+    }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/persist/EditLog.java 
b/fe/fe-core/src/main/java/org/apache/doris/persist/EditLog.java
index 4d119d0f5cd..be28a322e3a 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/persist/EditLog.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/persist/EditLog.java
@@ -1277,7 +1277,7 @@ public class EditLog {
                     TableBranchOrTagInfo info = (TableBranchOrTagInfo) 
journal.getData();
                     CatalogIf ctl = 
Env.getCurrentEnv().getCatalogMgr().getCatalog(info.getCtlName());
                     if (ctl != null) {
-                        ctl.replayCreateOrReplaceBranchOrTag(info.getDbName(), 
info.getTblName());
+                        ctl.replayOperateOnBranchOrTag(info.getDbName(), 
info.getTblName());
                     }
                     break;
                 }
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/datasource/iceberg/IcebergExternalTableBranchAndTagTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/datasource/iceberg/IcebergExternalTableBranchAndTagTest.java
index 4626b2e7b2d..3a65fe9cf6b 100644
--- 
a/fe/fe-core/src/test/java/org/apache/doris/datasource/iceberg/IcebergExternalTableBranchAndTagTest.java
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/datasource/iceberg/IcebergExternalTableBranchAndTagTest.java
@@ -22,6 +22,8 @@ import org.apache.doris.common.UserException;
 import org.apache.doris.nereids.trees.plans.commands.info.BranchOptions;
 import 
org.apache.doris.nereids.trees.plans.commands.info.CreateOrReplaceBranchInfo;
 import 
org.apache.doris.nereids.trees.plans.commands.info.CreateOrReplaceTagInfo;
+import org.apache.doris.nereids.trees.plans.commands.info.DropBranchInfo;
+import org.apache.doris.nereids.trees.plans.commands.info.DropTagInfo;
 import org.apache.doris.nereids.trees.plans.commands.info.TagOptions;
 import org.apache.doris.persist.EditLog;
 
@@ -71,7 +73,6 @@ public class IcebergExternalTableBranchAndTagTest {
         tempDirectory = Files.createTempDirectory("");
         map.put("warehouse", "file://" + tempDirectory.toString());
         map.put("type", "hadoop");
-        System.out.println(tempDirectory);
         icebergCatalog =
                 (HadoopCatalog) 
CatalogUtil.buildIcebergCatalog("iceberg_catalog", map, new Configuration());
 
@@ -354,4 +355,104 @@ public class IcebergExternalTableBranchAndTagTest {
         Assertions.assertEquals(minSnapshotsToKeep, ref.minSnapshotsToKeep());
         Assertions.assertEquals(maxRefAgeMs, ref.maxRefAgeMs());
     }
+
+    @Test
+    public void testDropBranchAndTag() throws IOException, UserException {
+        String tag1 = "tag1";
+        String tag2 = "tag2";
+        String branch1 = "branch1";
+        String branch2 = "branch2";
+        String tagNotExists = "tagNotExists";
+        String branchNotExists = "branchNotExists";
+
+        // create a new tag: tag1
+        addSomeDataIntoIcebergTable();
+        CreateOrReplaceTagInfo tagInfo =
+                new CreateOrReplaceTagInfo(tag1, true, false, false, 
TagOptions.EMPTY);
+        catalog.createOrReplaceTag(dbName, tblName, tagInfo);
+
+        // create a new branch: branch1
+        CreateOrReplaceBranchInfo branchInfo =
+                new CreateOrReplaceBranchInfo(branch1, true, false, false, 
BranchOptions.EMPTY);
+        catalog.createOrReplaceBranch(dbName, tblName, branchInfo);
+
+        // create a new tag: tag2
+        addSomeDataIntoIcebergTable();
+        CreateOrReplaceTagInfo tagInfo2 =
+                new CreateOrReplaceTagInfo(tag2, true, false, false, 
TagOptions.EMPTY);
+        catalog.createOrReplaceTag(dbName, tblName, tagInfo2);
+
+        // create a new branch: branch2
+        CreateOrReplaceBranchInfo branchInfo2 =
+                new CreateOrReplaceBranchInfo(branch2, true, false, false, 
BranchOptions.EMPTY);
+        catalog.createOrReplaceBranch(dbName, tblName, branchInfo2);
+
+        Assertions.assertEquals(5, icebergTable.refs().size());
+
+        Assertions.assertTrue(icebergTable.refs().containsKey(tag1));
+        Assertions.assertTrue(icebergTable.refs().get(tag1).isTag());
+
+        Assertions.assertTrue(icebergTable.refs().containsKey(tag2));
+        Assertions.assertTrue(icebergTable.refs().get(tag2).isTag());
+
+        Assertions.assertTrue(icebergTable.refs().containsKey(branch1));
+        Assertions.assertTrue(icebergTable.refs().get(branch1).isBranch());
+
+        Assertions.assertTrue(icebergTable.refs().containsKey(branch2));
+        Assertions.assertTrue(icebergTable.refs().get(branch2).isBranch());
+
+        // drop tag with branch interface, will fail
+        DropBranchInfo dropBranchInfoWithTag1 = new DropBranchInfo(tag1, 
false);
+        DropBranchInfo dropBranchInfoIfExistsWithTag1 = new 
DropBranchInfo(tag1, true);
+        Assertions.assertThrows(RuntimeException.class,
+                () -> catalog.dropBranch(dbName, tblName, 
dropBranchInfoWithTag1));
+        Assertions.assertThrows(RuntimeException.class,
+                () -> catalog.dropBranch(dbName, tblName, 
dropBranchInfoIfExistsWithTag1));
+
+        // drop branch with tag interface, will fail
+        DropTagInfo dropTagInfoWithBranch1 = new DropTagInfo(branch1, false);
+        DropTagInfo dropTagInfoWithBranchIfExists1 = new DropTagInfo(branch1, 
true);
+        Assertions.assertThrows(RuntimeException.class,
+                () -> catalog.dropTag(dbName, tblName, 
dropTagInfoWithBranch1));
+        Assertions.assertThrows(RuntimeException.class,
+                () -> catalog.dropTag(dbName, tblName, 
dropTagInfoWithBranchIfExists1));
+
+        // drop not exists tag
+        DropTagInfo dropTagInfoWithNotExistsTag1 = new 
DropTagInfo(tagNotExists, true);
+        DropTagInfo dropTagInfoWithNotExistsTag2 = new 
DropTagInfo(tagNotExists, false);
+        DropTagInfo dropTagInfoWithNotExistsBranch1 = new 
DropTagInfo(branchNotExists, true);
+        DropTagInfo dropTagInfoWithNotExistsBranch2 = new 
DropTagInfo(branchNotExists, false);
+        catalog.dropTag(dbName, tblName, dropTagInfoWithNotExistsTag1);
+        Assertions.assertThrows(RuntimeException.class,
+                () -> catalog.dropTag(dbName, tblName, 
dropTagInfoWithNotExistsTag2));
+        catalog.dropTag(dbName, tblName, dropTagInfoWithNotExistsBranch1);
+        Assertions.assertThrows(RuntimeException.class,
+                () -> catalog.dropTag(dbName, tblName, 
dropTagInfoWithNotExistsBranch2));
+
+        // drop not exists branch
+        DropBranchInfo dropBranchInfoWithNotExistsTag1 = new 
DropBranchInfo(tagNotExists, true);
+        DropBranchInfo dropBranchInfoWithNotExistsTag2 = new 
DropBranchInfo(tagNotExists, false);
+        DropBranchInfo dropBranchInfoIfExistsWithBranch1 = new 
DropBranchInfo(branchNotExists, true);
+        DropBranchInfo dropBranchInfoIfExistsWithBranch2 = new 
DropBranchInfo(branchNotExists, false);
+        catalog.dropBranch(dbName, tblName, dropBranchInfoWithNotExistsTag1);
+        Assertions.assertThrows(RuntimeException.class,
+                () -> catalog.dropBranch(dbName, tblName, 
dropBranchInfoWithNotExistsTag2));
+        catalog.dropBranch(dbName, tblName, dropBranchInfoIfExistsWithBranch1);
+        Assertions.assertThrows(RuntimeException.class,
+                () -> catalog.dropBranch(dbName, tblName, 
dropBranchInfoIfExistsWithBranch2));
+
+        // drop branch1 and branch2
+        DropBranchInfo dropBranchInfoWithBranch1 = new DropBranchInfo(branch1, 
false);
+        DropBranchInfo dropBranchInfoWithBranch2 = new DropBranchInfo(branch2, 
true);
+        catalog.dropBranch(dbName, tblName, dropBranchInfoWithBranch1);
+        catalog.dropBranch(dbName, tblName, dropBranchInfoWithBranch2);
+
+        // drop tag1 and tag2
+        DropTagInfo dropTagInfoWithTag1 = new DropTagInfo(tag1, false);
+        DropTagInfo dropTagInfoWithTag2 = new DropTagInfo(tag2, true);
+        catalog.dropTag(dbName, tblName, dropTagInfoWithTag1);
+        catalog.dropTag(dbName, tblName, dropTagInfoWithTag2);
+
+        Assertions.assertEquals(1, icebergTable.refs().size());
+    }
 }
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/commands/info/DropBranchOrTagInfoTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/commands/info/DropBranchOrTagInfoTest.java
new file mode 100644
index 00000000000..e30554dce0a
--- /dev/null
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/commands/info/DropBranchOrTagInfoTest.java
@@ -0,0 +1,52 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.trees.plans.commands.info;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class DropBranchOrTagInfoTest {
+
+    @Test
+    public void testDropTagToSql() {
+        DropTagInfo dropTagInfo = new DropTagInfo("tag", false);
+        String expected = "DROP TAG tag";
+        Assertions.assertEquals(expected, dropTagInfo.toSql());
+    }
+
+    @Test
+    public void testDropTagIfExistsToSql() {
+        DropTagInfo dropTagInfo = new DropTagInfo("tag", true);
+        String expected = "DROP TAG IF EXISTS tag";
+        Assertions.assertEquals(expected, dropTagInfo.toSql());
+    }
+
+    @Test
+    public void testDropBranchToSql() {
+        DropBranchInfo dropBranchInfo = new DropBranchInfo("branch", false);
+        String expected = "DROP BRANCH branch";
+        Assertions.assertEquals(expected, dropBranchInfo.toSql());
+    }
+
+    @Test
+    public void testDropBranchIfExistsToSql() {
+        DropBranchInfo dropBranchInfo = new DropBranchInfo("branch", true);
+        String expected = "DROP BRANCH IF EXISTS branch";
+        Assertions.assertEquals(expected, dropBranchInfo.toSql());
+    }
+}
diff --git 
a/regression-test/suites/external_table_p0/iceberg/iceberg_branch_tag_operate.groovy
 
b/regression-test/suites/external_table_p0/iceberg/iceberg_branch_tag_operate.groovy
index d96b2a08397..f5d38350e7a 100644
--- 
a/regression-test/suites/external_table_p0/iceberg/iceberg_branch_tag_operate.groovy
+++ 
b/regression-test/suites/external_table_p0/iceberg/iceberg_branch_tag_operate.groovy
@@ -191,4 +191,64 @@ suite("iceberg_branch_tag_operate", 
"p0,external,doris,external_docker,external_
 
     /// select by tag will use tag schema
     qt_sc06 """SELECT * FROM tmp_schema_change_branch@tag(test_tag) order by 
id;"""
+
+    // 
----------------------------------------------------------------------------------------
+    // test drop branch / tag
+    // 
----------------------------------------------------------------------------------------
+
+    test {
+        sql """ alter table test_branch_tag_operate drop branch if exists t2 
"""
+        exception "Ref t2 is a tag not a branch"
+    }
+
+    test {
+        sql """ alter table test_branch_tag_operate drop branch t2 """
+        exception "Ref t2 is a tag not a branch"
+    }
+
+    test {
+        sql """ alter table test_branch_tag_operate drop tag if exists b2 """
+        exception "Ref b2 is a branch not a tag"
+    }
+
+    test {
+        sql """ alter table test_branch_tag_operate drop tag b2 """
+        exception "Ref b2 is a branch not a tag"
+    }
+
+    sql """ alter table test_branch_tag_operate drop branch if exists 
not_exists_branch """
+    test {
+        sql """ alter table test_branch_tag_operate drop branch 
not_exists_branch """
+        exception "Branch does not exist: not_exists_branch"
+    }
+
+    sql """ alter table test_branch_tag_operate drop tag if exists 
not_exists_tag """
+    test {
+        sql """ alter table test_branch_tag_operate drop tag not_exists_tag """
+        exception "Tag does not exist: not_exists_tag"
+    }
+
+    // drop tag success, then read
+    sql """ alter table test_branch_tag_operate drop tag t2 """
+    sql """ alter table test_branch_tag_operate drop tag if exists t3 """
+    test {
+        sql """ select * from test_branch_tag_operate@tag(t2) """
+        exception "does not have tag named t2"
+    }
+    test {
+        sql """ select * from test_branch_tag_operate@tag(t3) """
+        exception "does not have tag named t3"
+    }
+
+    // drop branch success, then read
+    sql """ alter table test_branch_tag_operate drop branch b2 """
+    sql """ alter table test_branch_tag_operate drop branch if exists b3 """
+    test {
+        sql """ select * from test_branch_tag_operate@branch(b2) """
+        exception "does not have branch named b2"
+    }
+    test {
+        sql """ select * from test_branch_tag_operate@branch(b3) """
+        exception "does not have branch named b3"
+    }
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]


Reply via email to