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

deniskuzZ 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 db55599c770 HIVE-29816: Iceberg: MERGE INTO with WHEN MATCHED THEN 
DELETE incorrectly duplicates rows under Copy-On-Write delete mode (#6701)
db55599c770 is described below

commit db55599c7705a3bea28b4afdd0b17b25991be5b1
Author: Raghav Aggarwal <[email protected]>
AuthorDate: Sun Sep 13 18:18:42 2026 +0530

    HIVE-29816: Iceberg: MERGE INTO with WHEN MATCHED THEN DELETE incorrectly 
duplicates rows under Copy-On-Write delete mode (#6701)
---
 .../apache/iceberg/mr/hive/HiveIcebergSerDe.java   |   8 +-
 .../iceberg/mr/hive/writer/WriterBuilder.java      |   6 +-
 .../queries/positive/iceberg_mixed_write_modes.q   |  17 ++++
 .../src/test/queries/positive/row_lineage.q        |  36 +++++++
 .../positive/iceberg_mixed_write_modes.q.out       |  78 +++++++++++++++
 .../src/test/results/positive/row_lineage.q.out    | 106 +++++++++++++++++++++
 .../hadoop/hive/ql/exec/FileSinkOperator.java      |   2 +
 .../hadoop/hive/ql/parse/SemanticAnalyzer.java     |   7 ++
 .../apache/hadoop/hive/ql/plan/FileSinkDesc.java   |  11 +++
 .../HiveCustomStorageHandlerUtils.java             |  13 +++
 10 files changed, 277 insertions(+), 7 deletions(-)

diff --git 
a/iceberg/iceberg-handler/src/main/java/org/apache/iceberg/mr/hive/HiveIcebergSerDe.java
 
b/iceberg/iceberg-handler/src/main/java/org/apache/iceberg/mr/hive/HiveIcebergSerDe.java
index 68dc8541374..81a617f52fd 100644
--- 
a/iceberg/iceberg-handler/src/main/java/org/apache/iceberg/mr/hive/HiveIcebergSerDe.java
+++ 
b/iceberg/iceberg-handler/src/main/java/org/apache/iceberg/mr/hive/HiveIcebergSerDe.java
@@ -27,7 +27,7 @@
 import java.util.stream.Collectors;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.hive.conf.HiveConf;
-import org.apache.hadoop.hive.ql.Context;
+import org.apache.hadoop.hive.ql.Context.Operation;
 import org.apache.hadoop.hive.ql.metadata.RowLineageUtils;
 import 
org.apache.hadoop.hive.ql.security.authorization.HiveCustomStorageHandlerUtils;
 import org.apache.hadoop.hive.ql.session.SessionStateUtil;
@@ -158,7 +158,8 @@ public void initialize(Configuration conf, Properties 
serDeProperties,
   private static Schema projectedSchema(Configuration conf, Properties 
serDeProperties,
       Schema tableSchema, Map<String, String> jobConf) {
     String tableName = serDeProperties.getProperty(Catalogs.NAME);
-    Context.Operation operation = 
HiveCustomStorageHandlerUtils.getWriteOperation(conf::get, tableName);
+    Operation operation = 
HiveCustomStorageHandlerUtils.getWriteOperation(conf::get, tableName);
+    boolean copyOnWrite = 
HiveCustomStorageHandlerUtils.isCopyOnWrite(conf::get, tableName);
 
     if (operation == null) {
       jobConf.put(InputFormatConfig.CASE_SENSITIVE, "false");
@@ -179,8 +180,7 @@ private static Schema projectedSchema(Configuration conf, 
Properties serDeProper
         return projectedSchema;
       }
     }
-    boolean isCOW = IcebergTableUtil.isCopyOnWriteMode(operation, conf::get);
-    if (isCOW) {
+    if (copyOnWrite) {
       return getSchemaWithRowLineage(
           IcebergAcidUtil.createSerdeSchemaForDelete(tableSchema.columns(), 
false), conf);
     }
diff --git 
a/iceberg/iceberg-handler/src/main/java/org/apache/iceberg/mr/hive/writer/WriterBuilder.java
 
b/iceberg/iceberg-handler/src/main/java/org/apache/iceberg/mr/hive/writer/WriterBuilder.java
index f489d11d818..dbe10bc4401 100644
--- 
a/iceberg/iceberg-handler/src/main/java/org/apache/iceberg/mr/hive/writer/WriterBuilder.java
+++ 
b/iceberg/iceberg-handler/src/main/java/org/apache/iceberg/mr/hive/writer/WriterBuilder.java
@@ -73,6 +73,7 @@ public class WriterBuilder {
   private TaskAttemptID attemptID;
   private String queryId;
   private Operation operation;
+  private final boolean copyOnWrite;
 
   // A task may write multiple output files using multiple writers. Each of 
them must have a unique operationId.
   private static AtomicInteger operationNum = new AtomicInteger(0);
@@ -87,6 +88,7 @@ private WriterBuilder(Table table, UnaryOperator<String> ops) 
{
     this.tableName = ops.apply(Catalogs.NAME);
     this.context = new Context(table.properties(), ops, tableName);
     this.operation = HiveCustomStorageHandlerUtils.getWriteOperation(ops, 
tableName);
+    this.copyOnWrite = HiveCustomStorageHandlerUtils.isCopyOnWrite(ops, 
tableName);
     this.rewritableDeletes = () -> rewritableDeletes(ops);
   }
 
@@ -136,9 +138,7 @@ public HiveIcebergWriter build() {
         .build();
 
     HiveIcebergWriter writer;
-    boolean isCOW = IcebergTableUtil.isCopyOnWriteMode(operation, 
table.properties()::getOrDefault);
-
-    if (isCOW) {
+    if (copyOnWrite) {
       writer = new HiveIcebergCopyOnWriteRecordWriter(table, writerFactory, 
dataFileFactory, shouldAddRowLineageColumns,
           context);
     } else {
diff --git 
a/iceberg/iceberg-handler/src/test/queries/positive/iceberg_mixed_write_modes.q 
b/iceberg/iceberg-handler/src/test/queries/positive/iceberg_mixed_write_modes.q
new file mode 100644
index 00000000000..bee75235cef
--- /dev/null
+++ 
b/iceberg/iceberg-handler/src/test/queries/positive/iceberg_mixed_write_modes.q
@@ -0,0 +1,17 @@
+CREATE TABLE merge_source (id INT, data STRING);
+INSERT INTO merge_source VALUES (2, 'banana_source');
+
+CREATE TABLE ice_cow_merge_delete_only (id INT, data STRING)
+STORED BY ICEBERG
+TBLPROPERTIES ('format-version'='3', 'write.delete.mode'='copy-on-write');
+
+INSERT INTO ice_cow_merge_delete_only VALUES (1, 'apple'), (2, 'banana'), (3, 
'cherry');
+
+SELECT id, data FROM ice_cow_merge_delete_only ORDER BY id;
+
+MERGE INTO ice_cow_merge_delete_only t
+USING merge_source s
+ON t.id = s.id
+WHEN MATCHED THEN DELETE;
+
+SELECT id, data FROM ice_cow_merge_delete_only ORDER BY id;
diff --git a/iceberg/iceberg-handler/src/test/queries/positive/row_lineage.q 
b/iceberg/iceberg-handler/src/test/queries/positive/row_lineage.q
index b730a92d5c0..1d4f5480a05 100644
--- a/iceberg/iceberg-handler/src/test/queries/positive/row_lineage.q
+++ b/iceberg/iceberg-handler/src/test/queries/positive/row_lineage.q
@@ -134,3 +134,39 @@ DELETE FROM ice_cow_delete_part WHERE id = 2 OR id = 3;
 SELECT id, data, part, ROW__LINEAGE__ID, LAST__UPDATED__SEQUENCE__NUMBER
 FROM ice_cow_delete_part
 ORDER BY id;
+
+-- cow merge delete only
+CREATE TABLE merge_source (
+  id INT,
+  data STRING
+);
+
+INSERT INTO merge_source VALUES
+  (2, 'banana_source');
+
+CREATE TABLE ice_cow_merge_delete_only (
+  id INT,
+  data STRING
+)
+STORED BY iceberg
+TBLPROPERTIES ('format-version'='3', 'write.delete.mode'='copy-on-write');
+
+-- Snapshot 1: Sequence 1
+INSERT INTO ice_cow_merge_delete_only VALUES
+  (1, 'apple'),
+  (2, 'banana'),
+  (3, 'cherry');
+
+SELECT id, data, ROW__LINEAGE__ID, LAST__UPDATED__SEQUENCE__NUMBER
+FROM ice_cow_merge_delete_only
+ORDER BY id;
+
+MERGE INTO ice_cow_merge_delete_only t
+USING merge_source s
+ON t.id = s.id
+WHEN MATCHED THEN DELETE;
+
+-- Verification: id=1 and id=3 should perfectly retain their original lineage
+SELECT id, data, ROW__LINEAGE__ID, LAST__UPDATED__SEQUENCE__NUMBER
+FROM ice_cow_merge_delete_only
+ORDER BY id;
diff --git 
a/iceberg/iceberg-handler/src/test/results/positive/iceberg_mixed_write_modes.q.out
 
b/iceberg/iceberg-handler/src/test/results/positive/iceberg_mixed_write_modes.q.out
new file mode 100644
index 00000000000..d77a5e65840
--- /dev/null
+++ 
b/iceberg/iceberg-handler/src/test/results/positive/iceberg_mixed_write_modes.q.out
@@ -0,0 +1,78 @@
+PREHOOK: query: CREATE TABLE merge_source (id INT, data STRING)
+PREHOOK: type: CREATETABLE
+PREHOOK: Output: database:default
+PREHOOK: Output: default@merge_source
+POSTHOOK: query: CREATE TABLE merge_source (id INT, data STRING)
+POSTHOOK: type: CREATETABLE
+POSTHOOK: Output: database:default
+POSTHOOK: Output: default@merge_source
+PREHOOK: query: INSERT INTO merge_source VALUES (2, 'banana_source')
+PREHOOK: type: QUERY
+PREHOOK: Input: _dummy_database@_dummy_table
+PREHOOK: Output: default@merge_source
+POSTHOOK: query: INSERT INTO merge_source VALUES (2, 'banana_source')
+POSTHOOK: type: QUERY
+POSTHOOK: Input: _dummy_database@_dummy_table
+POSTHOOK: Output: default@merge_source
+POSTHOOK: Lineage: merge_source.data SCRIPT []
+POSTHOOK: Lineage: merge_source.id SCRIPT []
+PREHOOK: query: CREATE TABLE ice_cow_merge_delete_only (id INT, data STRING)
+STORED BY ICEBERG
+TBLPROPERTIES ('format-version'='3', 'write.delete.mode'='copy-on-write')
+PREHOOK: type: CREATETABLE
+PREHOOK: Output: database:default
+PREHOOK: Output: default@ice_cow_merge_delete_only
+POSTHOOK: query: CREATE TABLE ice_cow_merge_delete_only (id INT, data STRING)
+STORED BY ICEBERG
+TBLPROPERTIES ('format-version'='3', 'write.delete.mode'='copy-on-write')
+POSTHOOK: type: CREATETABLE
+POSTHOOK: Output: database:default
+POSTHOOK: Output: default@ice_cow_merge_delete_only
+PREHOOK: query: INSERT INTO ice_cow_merge_delete_only VALUES (1, 'apple'), (2, 
'banana'), (3, 'cherry')
+PREHOOK: type: QUERY
+PREHOOK: Input: _dummy_database@_dummy_table
+PREHOOK: Output: default@ice_cow_merge_delete_only
+POSTHOOK: query: INSERT INTO ice_cow_merge_delete_only VALUES (1, 'apple'), 
(2, 'banana'), (3, 'cherry')
+POSTHOOK: type: QUERY
+POSTHOOK: Input: _dummy_database@_dummy_table
+POSTHOOK: Output: default@ice_cow_merge_delete_only
+PREHOOK: query: SELECT id, data FROM ice_cow_merge_delete_only ORDER BY id
+PREHOOK: type: QUERY
+PREHOOK: Input: default@ice_cow_merge_delete_only
+PREHOOK: Output: hdfs://### HDFS PATH ###
+POSTHOOK: query: SELECT id, data FROM ice_cow_merge_delete_only ORDER BY id
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@ice_cow_merge_delete_only
+POSTHOOK: Output: hdfs://### HDFS PATH ###
+1      apple
+2      banana
+3      cherry
+PREHOOK: query: MERGE INTO ice_cow_merge_delete_only t
+USING merge_source s
+ON t.id = s.id
+WHEN MATCHED THEN DELETE
+PREHOOK: type: QUERY
+PREHOOK: Input: default@ice_cow_merge_delete_only
+PREHOOK: Input: default@merge_source
+PREHOOK: Output: default@ice_cow_merge_delete_only
+PREHOOK: Output: default@merge_tmp_table
+POSTHOOK: query: MERGE INTO ice_cow_merge_delete_only t
+USING merge_source s
+ON t.id = s.id
+WHEN MATCHED THEN DELETE
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@ice_cow_merge_delete_only
+POSTHOOK: Input: default@merge_source
+POSTHOOK: Output: default@ice_cow_merge_delete_only
+POSTHOOK: Output: default@merge_tmp_table
+POSTHOOK: Lineage: merge_tmp_table.val EXPRESSION 
[(ice_cow_merge_delete_only)ice_cow_merge_delete_only.null, ]
+PREHOOK: query: SELECT id, data FROM ice_cow_merge_delete_only ORDER BY id
+PREHOOK: type: QUERY
+PREHOOK: Input: default@ice_cow_merge_delete_only
+PREHOOK: Output: hdfs://### HDFS PATH ###
+POSTHOOK: query: SELECT id, data FROM ice_cow_merge_delete_only ORDER BY id
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@ice_cow_merge_delete_only
+POSTHOOK: Output: hdfs://### HDFS PATH ###
+1      apple
+3      cherry
diff --git 
a/iceberg/iceberg-handler/src/test/results/positive/row_lineage.q.out 
b/iceberg/iceberg-handler/src/test/results/positive/row_lineage.q.out
index 59308a02872..5275d3baab4 100644
--- a/iceberg/iceberg-handler/src/test/results/positive/row_lineage.q.out
+++ b/iceberg/iceberg-handler/src/test/results/positive/row_lineage.q.out
@@ -469,3 +469,109 @@ POSTHOOK: Output: hdfs://### HDFS PATH ###
 1      apple   p1      0       1
 4      date    p2      3       1
 5      elderberry      p1      4       2
+PREHOOK: query: CREATE TABLE merge_source (
+  id INT,
+  data STRING
+)
+PREHOOK: type: CREATETABLE
+PREHOOK: Output: database:default
+PREHOOK: Output: default@merge_source
+POSTHOOK: query: CREATE TABLE merge_source (
+  id INT,
+  data STRING
+)
+POSTHOOK: type: CREATETABLE
+POSTHOOK: Output: database:default
+POSTHOOK: Output: default@merge_source
+PREHOOK: query: INSERT INTO merge_source VALUES
+  (2, 'banana_source')
+PREHOOK: type: QUERY
+PREHOOK: Input: _dummy_database@_dummy_table
+PREHOOK: Output: default@merge_source
+POSTHOOK: query: INSERT INTO merge_source VALUES
+  (2, 'banana_source')
+POSTHOOK: type: QUERY
+POSTHOOK: Input: _dummy_database@_dummy_table
+POSTHOOK: Output: default@merge_source
+POSTHOOK: Lineage: merge_source.data SCRIPT []
+POSTHOOK: Lineage: merge_source.id SCRIPT []
+PREHOOK: query: CREATE TABLE ice_cow_merge_delete_only (
+  id INT,
+  data STRING
+)
+STORED BY iceberg
+TBLPROPERTIES ('format-version'='3', 'write.delete.mode'='copy-on-write')
+PREHOOK: type: CREATETABLE
+PREHOOK: Output: database:default
+PREHOOK: Output: default@ice_cow_merge_delete_only
+POSTHOOK: query: CREATE TABLE ice_cow_merge_delete_only (
+  id INT,
+  data STRING
+)
+STORED BY iceberg
+TBLPROPERTIES ('format-version'='3', 'write.delete.mode'='copy-on-write')
+POSTHOOK: type: CREATETABLE
+POSTHOOK: Output: database:default
+POSTHOOK: Output: default@ice_cow_merge_delete_only
+PREHOOK: query: INSERT INTO ice_cow_merge_delete_only VALUES
+  (1, 'apple'),
+  (2, 'banana'),
+  (3, 'cherry')
+PREHOOK: type: QUERY
+PREHOOK: Input: _dummy_database@_dummy_table
+PREHOOK: Output: default@ice_cow_merge_delete_only
+POSTHOOK: query: INSERT INTO ice_cow_merge_delete_only VALUES
+  (1, 'apple'),
+  (2, 'banana'),
+  (3, 'cherry')
+POSTHOOK: type: QUERY
+POSTHOOK: Input: _dummy_database@_dummy_table
+POSTHOOK: Output: default@ice_cow_merge_delete_only
+PREHOOK: query: SELECT id, data, ROW__LINEAGE__ID, 
LAST__UPDATED__SEQUENCE__NUMBER
+FROM ice_cow_merge_delete_only
+ORDER BY id
+PREHOOK: type: QUERY
+PREHOOK: Input: default@ice_cow_merge_delete_only
+PREHOOK: Output: hdfs://### HDFS PATH ###
+POSTHOOK: query: SELECT id, data, ROW__LINEAGE__ID, 
LAST__UPDATED__SEQUENCE__NUMBER
+FROM ice_cow_merge_delete_only
+ORDER BY id
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@ice_cow_merge_delete_only
+POSTHOOK: Output: hdfs://### HDFS PATH ###
+1      apple   0       1
+2      banana  1       1
+3      cherry  2       1
+PREHOOK: query: MERGE INTO ice_cow_merge_delete_only t
+USING merge_source s
+ON t.id = s.id
+WHEN MATCHED THEN DELETE
+PREHOOK: type: QUERY
+PREHOOK: Input: default@ice_cow_merge_delete_only
+PREHOOK: Input: default@merge_source
+PREHOOK: Output: default@ice_cow_merge_delete_only
+PREHOOK: Output: default@merge_tmp_table
+POSTHOOK: query: MERGE INTO ice_cow_merge_delete_only t
+USING merge_source s
+ON t.id = s.id
+WHEN MATCHED THEN DELETE
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@ice_cow_merge_delete_only
+POSTHOOK: Input: default@merge_source
+POSTHOOK: Output: default@ice_cow_merge_delete_only
+POSTHOOK: Output: default@merge_tmp_table
+POSTHOOK: Lineage: merge_tmp_table.val EXPRESSION 
[(ice_cow_merge_delete_only)ice_cow_merge_delete_only.null, ]
+PREHOOK: query: SELECT id, data, ROW__LINEAGE__ID, 
LAST__UPDATED__SEQUENCE__NUMBER
+FROM ice_cow_merge_delete_only
+ORDER BY id
+PREHOOK: type: QUERY
+PREHOOK: Input: default@ice_cow_merge_delete_only
+PREHOOK: Output: hdfs://### HDFS PATH ###
+POSTHOOK: query: SELECT id, data, ROW__LINEAGE__ID, 
LAST__UPDATED__SEQUENCE__NUMBER
+FROM ice_cow_merge_delete_only
+ORDER BY id
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@ice_cow_merge_delete_only
+POSTHOOK: Output: hdfs://### HDFS PATH ###
+1      apple   0       1
+3      cherry  2       1
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/exec/FileSinkOperator.java 
b/ql/src/java/org/apache/hadoop/hive/ql/exec/FileSinkOperator.java
index 8a6b9680258..b097ec8c65d 100644
--- a/ql/src/java/org/apache/hadoop/hive/ql/exec/FileSinkOperator.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/exec/FileSinkOperator.java
@@ -21,6 +21,7 @@
 
 import static 
org.apache.hadoop.hive.conf.HiveConf.ConfVars.HIVE_TEMPORARY_TABLE_STORAGE;
 import static 
org.apache.hadoop.hive.ql.security.authorization.HiveCustomStorageHandlerUtils.MERGE_TASK_ENABLED;
+import static 
org.apache.hadoop.hive.ql.security.authorization.HiveCustomStorageHandlerUtils.setCopyOnWrite;
 import static 
org.apache.hadoop.hive.ql.security.authorization.HiveCustomStorageHandlerUtils.setMergeTaskEnabled;
 import static 
org.apache.hadoop.hive.ql.security.authorization.HiveCustomStorageHandlerUtils.setWriteOperation;
 import static 
org.apache.hadoop.hive.ql.security.authorization.HiveCustomStorageHandlerUtils.setWriteOperationIsSorted;
@@ -640,6 +641,7 @@ protected void initializeOp(Configuration hconf) throws 
HiveException {
 
       jc = new JobConf(hconf);
       setWriteOperation(jc, getConf().getTableInfo().getTableName(), 
getConf().getWriteOperation());
+      setCopyOnWrite(jc, getConf().getTableInfo().getTableName(), 
getConf().isCopyOnWrite());
       setWriteOperationIsSorted(jc, getConf().getTableInfo().getTableName(),
               dpCtx != null && dpCtx.hasCustomPartitionOrSortExpression());
       setMergeTaskEnabled(jc, getConf().getTableInfo().getTableName(),
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/parse/SemanticAnalyzer.java 
b/ql/src/java/org/apache/hadoop/hive/ql/parse/SemanticAnalyzer.java
index ff9e9f25320..9139355fe47 100644
--- a/ql/src/java/org/apache/hadoop/hive/ql/parse/SemanticAnalyzer.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/parse/SemanticAnalyzer.java
@@ -8661,6 +8661,13 @@ private FileSinkDesc createFileSinkDesc(String dest, 
TableDesc table_desc,
     }
 
     fileSinkDesc.setWriteOperation(writeOperation);
+    if (writeOperation != Context.Operation.OTHER
+        && dest_tab != null
+        && dest_tab.getStorageHandler() != null) {
+      boolean copyOnWrite =
+          dest_tab.getStorageHandler().shouldOverwrite(dest_tab, 
ctx.getOperation());
+      fileSinkDesc.setCopyOnWrite(copyOnWrite);
+    }
 
     fileSinkDesc.setTemporary(destTableIsTemporary);
     fileSinkDesc.setMaterialization(destTableIsMaterialization);
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/plan/FileSinkDesc.java 
b/ql/src/java/org/apache/hadoop/hive/ql/plan/FileSinkDesc.java
index 4074df3666c..d1df0e8c01e 100644
--- a/ql/src/java/org/apache/hadoop/hive/ql/plan/FileSinkDesc.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/plan/FileSinkDesc.java
@@ -112,6 +112,7 @@ public enum DPSortState {
   private Path destPath;
   private boolean isHiveServerQuery;
   private boolean isMerge;
+  private boolean copyOnWrite = false;
   private boolean isMmCtas;
 
   private Set<FileStatus> filesToFetch = null;
@@ -199,6 +200,8 @@ public Object clone() throws CloneNotSupportedException {
     ret.setStatsReliable(statsReliable);
     ret.setDpSortState(dpSortState);
     ret.setWriteType(writeType);
+    ret.setWriteOperation(writeOperation);
+    ret.setCopyOnWrite(copyOnWrite);
     ret.setTableWriteId(tableWriteId);
     ret.setStatementId(statementId);
     ret.setStatsTmpDir(statsTmpDir);
@@ -686,6 +689,14 @@ public boolean isMmCtas() {
     return isMmCtas;
   }
 
+  public void setCopyOnWrite(boolean copyOnWrite) {
+    this.copyOnWrite = copyOnWrite;
+  }
+
+  public boolean isCopyOnWrite() {
+    return copyOnWrite;
+  }
+
   @Explain(displayName = "bucketingVersion", explainLevels = { Level.EXTENDED 
})
   public int getBucketingVersionForExplain() {
     return getBucketingVersion();
diff --git 
a/ql/src/java/org/apache/hadoop/hive/ql/security/authorization/HiveCustomStorageHandlerUtils.java
 
b/ql/src/java/org/apache/hadoop/hive/ql/security/authorization/HiveCustomStorageHandlerUtils.java
index 90af599a199..57302b13da7 100644
--- 
a/ql/src/java/org/apache/hadoop/hive/ql/security/authorization/HiveCustomStorageHandlerUtils.java
+++ 
b/ql/src/java/org/apache/hadoop/hive/ql/security/authorization/HiveCustomStorageHandlerUtils.java
@@ -33,6 +33,7 @@ public class HiveCustomStorageHandlerUtils {
 
   public static final String WRITE_OPERATION_CONFIG_PREFIX = 
"file.sink.write.operation.";
   public static final String WRITE_OPERATION_IS_SORTED = 
"file.sink.write.operation.sorted.";
+  public static final String IS_COPY_ON_WRITE_CONFIG_PREFIX = 
"file.sink.is.copy.on.write.";
 
   public static final String MERGE_TASK_ENABLED = 
"file.sink.merge.task.enabled.";
 
@@ -96,4 +97,16 @@ public static boolean 
isMergeTaskEnabled(UnaryOperator<String> ops, String table
     String operation = ops.apply(MERGE_TASK_ENABLED + tableName);
     return Boolean.parseBoolean(operation);
   }
+
+  public static void setCopyOnWrite(Configuration conf, String tableName, 
boolean copyOnWrite) {
+    if (conf == null || tableName == null) {
+      return;
+    }
+    conf.setBoolean(IS_COPY_ON_WRITE_CONFIG_PREFIX + tableName, copyOnWrite);
+  }
+
+  public static boolean isCopyOnWrite(UnaryOperator<String> ops, String 
tableName) {
+    String isCopyOnWrite = ops.apply(IS_COPY_ON_WRITE_CONFIG_PREFIX + 
tableName);
+    return Boolean.parseBoolean(isCopyOnWrite);
+  }
 }

Reply via email to