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]