HIVE-29816: Iceberg: MERGE INTO with WHEN MATCHED THEN DELETE incorrectly duplicates rows under Copy-On-Write delete mode - #6701
Conversation
|
@ayushtkn , can you help with review? |
|
@deniskuzZ , can you please help with review? |
|
@Aggarwal-Raghav, sure, please give me some time |
understood |
4e6163e to
fc5b28a
Compare
| setWriteOperation(jc, getConf().getTableInfo().getTableName(), getConf().getWriteOperation()); | ||
| setStatementOperation(jc, getConf().getTableInfo().getTableName(), getConf().getStatementOperation()); |
There was a problem hiding this comment.
Why are both WriteOperation and StatementOperation needed? Aren't they the same?
There was a problem hiding this comment.
Hey @kasakrisz ,
StatementOperation represents the top-level intent during query compilation. For example: If a MERGE query is fired from Beeline, then StatementOperation = MERGE.
During Query execution, if the table is configured with write.merge.mode=COW and write.delete.mode=MOR, then MERGE query is splitted into INSERT and DELETE Branch (writeOperation = DELETE) and its incorrectly picking write.delete.mode instead of write.merge.mode.
The aim of this PR is to pass the top-level query operation (StatementOperation) from the compilation layer down to the execution layer so it honor correct iceberg table property.
There was a problem hiding this comment.
@kasakrisz do you have in mind alternative solution?
There was a problem hiding this comment.
ctx.getOperation() and queryState.getHiveOperation() will not match because for MERGE, Update or SELECT queryState.getHiveOperation() will return HiveOperation.QUERY.
queryState.getHiveOperation() is used extensively in LineageLogger (I've worked on that previously).
To test it I added this in SemanticAnalyzer#createFileSinkDesc() and re-ran the iceberg_mixed_write_modes.q file
LOG.info("TESTING_OPERATIONS: ctx.getOperation() = " + ctx.getOperation() + ", queryState.getHiveOperation() = " + queryState.getHiveOperation());| boolean isCOW = IcebergTableUtil.isCopyOnWriteMode(operation, table.properties()::getOrDefault); | ||
| boolean isCOW = | ||
| IcebergTableUtil.isCopyOnWriteMode( | ||
| statementOperation != null ? statementOperation : writeOperation, |
There was a problem hiding this comment.
ObjectUtils.defaultIfNull(statementOperation, writeOperation) ?
| } | ||
| boolean isCOW = IcebergTableUtil.isCopyOnWriteMode(operation, conf::get); | ||
| boolean isCOW = IcebergTableUtil.isCopyOnWriteMode( | ||
| statementOperation != null ? statementOperation : writeOperation, conf::get); |
07a1f23 to
0d2a7f2
Compare
- Revert `writeOperation` back to `operation` in WriterBuilder and HiveIcebergSerDe - Use `ObjectUtils.defaultIfNull` instead of ternary operators. - Extract `operation` fallback checks into local variables to improve readability and avoid spotless line wrapping. - Update imports to use `Operation` directly instead of `Context.Operation`.
0af100f to
bd256ff
Compare
|
rebased with master due to merge conflict becuase of HIVE-29815 |
| private TaskAttemptID attemptID; | ||
| private String queryId; | ||
| private Operation operation; | ||
| private final boolean isCopyOnWrite; |
There was a problem hiding this comment.
nit: AFAIK the boolean field name doesn't need the is prefix. The getter has it.
field: boolean copyOnWrite;
getter: isCopyOnWrite()
setter: setCopyOnWrite(boolean)
| private Path destPath; | ||
| private boolean isHiveServerQuery; | ||
| private boolean isMerge; | ||
| private boolean isCopyOnWrite = false; |
There was a problem hiding this comment.
nit.
field: boolean copyOnWrite;
getter: isCopyOnWrite()
setter: setCopyOnWrite(boolean)
See other boolean fields
hive/ql/src/java/org/apache/hadoop/hive/ql/plan/FileSinkDesc.java
Lines 65 to 67 in 2be30b7
hive/ql/src/java/org/apache/hadoop/hive/ql/plan/FileSinkDesc.java
Lines 352 to 372 in 2be30b7
| return Boolean.parseBoolean(operation); | ||
| } | ||
|
|
||
| public static void setIsCopyOnWrite(Configuration conf, String tableName, boolean isCopyOnWrite) { |
b561e60 to
2caf84e
Compare
2caf84e to
f171f3e
Compare
|








What changes were proposed in this pull request?
When
write.delete.mode=copy-on-writeandwrite.merge.mode=merge-on-read(default), running aMERGE INTO ... WHEN MATCHED THEN DELETEquery incorrectly causes the writer to use COW instead of MOR causing duplicate rows instead of deleting the rows.Added an
isMergeStatementboolean flag toFileSinkDescand propagated it to the Hadoop JobConf duringFileSinkOperatorinitialization viaHiveCustomStorageHandlerUtils.setIsMergeStatementWhy are the changes needed?
Check HIVE-29816
Does this PR introduce any user-facing change?
Yes, executing
MERGE INTO... DELETEquery on tables utilizingCopy-On-Writedelete modes will no longer experience data duplication and sequence number increments.How was this patch tested?
Using, q files and on spark