You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hive.apache.org by ay...@apache.org on 2024/06/26 10:45:34 UTC

(hive) branch master updated: HIVE-28275: Iceberg: Add support for 'If Not Exists' and 'or Replace' for Create Tag. (#5317). (Ayush Saxena, reviewed by Simhadri Govindappa)

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

ayushsaxena pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/hive.git


The following commit(s) were added to refs/heads/master by this push:
     new 74b9c88aced HIVE-28275: Iceberg: Add support for 'If Not Exists' and 'or Replace' for Create Tag. (#5317). (Ayush Saxena, reviewed by Simhadri Govindappa)
74b9c88aced is described below

commit 74b9c88aced9407351f6635769a4bd48214fca1e
Author: Ayush Saxena <ay...@apache.org>
AuthorDate: Wed Jun 26 16:15:29 2024 +0530

    HIVE-28275: Iceberg: Add support for 'If Not Exists' and 'or Replace' for Create Tag. (#5317). (Ayush Saxena, reviewed by Simhadri Govindappa)
---
 .../iceberg/mr/hive/IcebergSnapshotRefExec.java    | 27 ++++++++++-
 .../test/queries/positive/alter_table_create_tag.q |  9 ++++
 .../results/positive/alter_table_create_tag.q.out  | 52 ++++++++++++++++++++++
 .../hadoop/hive/ql/parse/AlterClauseParser.g       | 12 ++++-
 4 files changed, 96 insertions(+), 4 deletions(-)

diff --git a/iceberg/iceberg-handler/src/main/java/org/apache/iceberg/mr/hive/IcebergSnapshotRefExec.java b/iceberg/iceberg-handler/src/main/java/org/apache/iceberg/mr/hive/IcebergSnapshotRefExec.java
index 3e251913801..9d3af3b45c5 100644
--- a/iceberg/iceberg-handler/src/main/java/org/apache/iceberg/mr/hive/IcebergSnapshotRefExec.java
+++ b/iceberg/iceberg-handler/src/main/java/org/apache/iceberg/mr/hive/IcebergSnapshotRefExec.java
@@ -103,6 +103,19 @@ public class IcebergSnapshotRefExec {
     }
   }
 
+  private static boolean refExistsAsTag(Table table, String tagName) {
+    SnapshotRef tagRef = table.refs().get(tagName);
+    if (tagRef != null) {
+      if (tagRef.isTag()) {
+        return true;
+      } else {
+        throw new IllegalArgumentException(
+            "Cannot complete create tag operation on " + tagName + ", as it exists as Branch");
+      }
+    }
+    return false;
+  }
+
   private static boolean refExistsAsBranch(Table table, String branchName) {
     SnapshotRef branchRef = table.refs().get(branchName);
     if (branchRef != null) {
@@ -154,6 +167,11 @@ public class IcebergSnapshotRefExec {
 
   public static void createTag(Table table, AlterTableSnapshotRefSpec.CreateSnapshotRefSpec createTagSpec) {
     String tagName = createTagSpec.getRefName();
+    boolean refExistsAsTag = refExistsAsTag(table, tagName);
+    if (createTagSpec.isIfNotExists() && refExistsAsTag) {
+      return;
+    }
+    boolean isReplace = createTagSpec.isReplace() && refExistsAsTag;
     Long snapshotId = null;
     if (createTagSpec.getSnapshotId() != null) {
       snapshotId = createTagSpec.getSnapshotId();
@@ -162,9 +180,14 @@ public class IcebergSnapshotRefExec {
     } else {
       snapshotId = table.currentSnapshot().snapshotId();
     }
-    LOG.info("Creating tag {} on iceberg table {} with snapshotId {}", tagName, table.name(), snapshotId);
     ManageSnapshots manageSnapshots = table.manageSnapshots();
-    manageSnapshots.createTag(tagName, snapshotId);
+    if (isReplace) {
+      LOG.info("Replacing tag {} on iceberg table {} with snapshotId {}", tagName, table.name(), snapshotId);
+      manageSnapshots.replaceTag(tagName, snapshotId);
+    } else {
+      LOG.info("Creating tag {} on iceberg table {} with snapshotId {}", tagName, table.name(), snapshotId);
+      manageSnapshots.createTag(tagName, snapshotId);
+    }
     if (createTagSpec.getMaxRefAgeMs() != null) {
       manageSnapshots.setMaxRefAgeMs(tagName, createTagSpec.getMaxRefAgeMs());
     }
diff --git a/iceberg/iceberg-handler/src/test/queries/positive/alter_table_create_tag.q b/iceberg/iceberg-handler/src/test/queries/positive/alter_table_create_tag.q
index ad5eabb3e8b..2ef424aeeb1 100644
--- a/iceberg/iceberg-handler/src/test/queries/positive/alter_table_create_tag.q
+++ b/iceberg/iceberg-handler/src/test/queries/positive/alter_table_create_tag.q
@@ -17,6 +17,15 @@ explain alter table iceTbl create tag test_tag_2 retain 5 days;
 alter table iceTbl create tag test_tag_2 retain 5 days;
 select name, max_reference_age_in_ms from default.iceTbl.refs where type='TAG';
 
+-- create a tag which already exists
+explain alter table iceTbl create tag if not exists test_tag_2;
+alter table iceTbl create tag if not exists test_tag_2;
+
+-- create or replace
+explain alter table iceTbl create or replace tag test_tag_1;
+alter table iceTbl create or replace tag test_tag_1;
+select * from default.iceTbl.tag_test_tag_1;
+
 -- drop a tag
 explain alter table iceTbl drop tag test_tag_2;
 alter table iceTbl drop tag test_tag_2;
diff --git a/iceberg/iceberg-handler/src/test/results/positive/alter_table_create_tag.q.out b/iceberg/iceberg-handler/src/test/results/positive/alter_table_create_tag.q.out
index 803891e4b28..38a4e3dd45c 100644
--- a/iceberg/iceberg-handler/src/test/results/positive/alter_table_create_tag.q.out
+++ b/iceberg/iceberg-handler/src/test/results/positive/alter_table_create_tag.q.out
@@ -83,6 +83,58 @@ POSTHOOK: Input: default@icetbl
 POSTHOOK: Output: hdfs://### HDFS PATH ###
 test_tag_1	NULL
 test_tag_2	432000000
+PREHOOK: query: explain alter table iceTbl create tag if not exists test_tag_2
+PREHOOK: type: ALTERTABLE_CREATETAG
+PREHOOK: Input: default@icetbl
+POSTHOOK: query: explain alter table iceTbl create tag if not exists test_tag_2
+POSTHOOK: type: ALTERTABLE_CREATETAG
+POSTHOOK: Input: default@icetbl
+STAGE DEPENDENCIES:
+  Stage-0 is a root stage
+
+STAGE PLANS:
+  Stage: Stage-0
+    SnapshotRef Operation
+      table name: default.iceTbl
+      spec: AlterTableSnapshotRefSpec{operationType=CREATE_TAG, operationParams=CreateSnapshotRefSpec{refName=test_tag_2, isReplace=false, ifNotExists=true}}
+
+PREHOOK: query: alter table iceTbl create tag if not exists test_tag_2
+PREHOOK: type: ALTERTABLE_CREATETAG
+PREHOOK: Input: default@icetbl
+POSTHOOK: query: alter table iceTbl create tag if not exists test_tag_2
+POSTHOOK: type: ALTERTABLE_CREATETAG
+POSTHOOK: Input: default@icetbl
+PREHOOK: query: explain alter table iceTbl create or replace tag test_tag_1
+PREHOOK: type: ALTERTABLE_CREATETAG
+PREHOOK: Input: default@icetbl
+POSTHOOK: query: explain alter table iceTbl create or replace tag test_tag_1
+POSTHOOK: type: ALTERTABLE_CREATETAG
+POSTHOOK: Input: default@icetbl
+STAGE DEPENDENCIES:
+  Stage-0 is a root stage
+
+STAGE PLANS:
+  Stage: Stage-0
+    SnapshotRef Operation
+      table name: default.iceTbl
+      spec: AlterTableSnapshotRefSpec{operationType=CREATE_TAG, operationParams=CreateSnapshotRefSpec{refName=test_tag_1, isReplace=true, ifNotExists=false}}
+
+PREHOOK: query: alter table iceTbl create or replace tag test_tag_1
+PREHOOK: type: ALTERTABLE_CREATETAG
+PREHOOK: Input: default@icetbl
+POSTHOOK: query: alter table iceTbl create or replace tag test_tag_1
+POSTHOOK: type: ALTERTABLE_CREATETAG
+POSTHOOK: Input: default@icetbl
+PREHOOK: query: select * from default.iceTbl.tag_test_tag_1
+PREHOOK: type: QUERY
+PREHOOK: Input: default@icetbl
+PREHOOK: Output: hdfs://### HDFS PATH ###
+POSTHOOK: query: select * from default.iceTbl.tag_test_tag_1
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@icetbl
+POSTHOOK: Output: hdfs://### HDFS PATH ###
+1	jack
+2	bob
 PREHOOK: query: explain alter table iceTbl drop tag test_tag_2
 PREHOOK: type: ALTERTABLE_DROPTAG
 PREHOOK: Input: default@icetbl
diff --git a/parser/src/java/org/apache/hadoop/hive/ql/parse/AlterClauseParser.g b/parser/src/java/org/apache/hadoop/hive/ql/parse/AlterClauseParser.g
index 2f136a5d998..65a35c2e0b7 100644
--- a/parser/src/java/org/apache/hadoop/hive/ql/parse/AlterClauseParser.g
+++ b/parser/src/java/org/apache/hadoop/hive/ql/parse/AlterClauseParser.g
@@ -75,6 +75,7 @@ alterTableStatementSuffix
     | alterStatementSuffixSetOwner
     | alterStatementSuffixSetPartSpec
     | alterStatementSuffixExecute
+    | (KW_CREATE KW_OR KW_REPLACE KW_TAG) => alterStatementSuffixCreateOrReplaceTag
     | alterStatementSuffixCreateBranch
     | alterStatementSuffixDropBranch
     | alterStatementSuffixCreateTag
@@ -582,10 +583,17 @@ alterStatementSuffixDropTag
 alterStatementSuffixCreateTag
 @init { gParent.pushMsg("alter table create tag", state); }
 @after { gParent.popMsg(state); }
-    : KW_CREATE KW_TAG tagName=identifier snapshotIdOfRef? refRetain?
-    -> ^(TOK_ALTERTABLE_CREATE_TAG $tagName snapshotIdOfRef? refRetain?)
+    : KW_CREATE KW_TAG ifNotExists? tagName=identifier snapshotIdOfRef? refRetain?
+    -> ^(TOK_ALTERTABLE_CREATE_TAG $tagName ifNotExists? snapshotIdOfRef? refRetain?)
     ;
 
+alterStatementSuffixCreateOrReplaceTag
+@init { gParent.pushMsg("alter table create tag", state); }
+@after { gParent.popMsg(state); }
+     : KW_CREATE KW_OR KW_REPLACE KW_TAG tagName=identifier snapshotIdOfRef? refRetain?
+     -> ^(TOK_ALTERTABLE_CREATE_TAG $tagName KW_REPLACE snapshotIdOfRef? refRetain?)
+     ;
+
 fileFormat
 @init { gParent.pushMsg("file format specification", state); }
 @after { gParent.popMsg(state); }