Description
A direct MIN_DELTA table stream on a MOW UNIQUE KEY table emits UPDATE_BEFORE and UPDATE_AFTER when a key is inserted again after its delete event has already been consumed. From the logical table perspective, the second write should be an APPEND.
This reproduces without IVM and without materialized-view complete refresh.
Reproduction
CREATE TABLE base_table (
k1 INT,
v1 INT
) UNIQUE KEY(k1)
DISTRIBUTED BY HASH(k1) BUCKETS 1
PROPERTIES (
"replication_num" = "1",
"binlog.enable" = "true",
"binlog.format" = "ROW",
"binlog.need_historical_value" = "true",
"enable_unique_key_merge_on_write" = "true"
);
CREATE STREAM base_stream ON TABLE base_table
PROPERTIES ("type" = "min_delta");
CREATE TABLE tmp_table (k1 INT, v1 INT)
DUPLICATE KEY(k1)
DISTRIBUTED BY HASH(k1) BUCKETS 1
PROPERTIES ("replication_num" = "1");
INSERT INTO base_table VALUES (1, 10);
DELETE FROM base_table WHERE k1 = 1;
INSERT INTO tmp_table SELECT * FROM base_stream;
INSERT INTO base_table VALUES (1, 10);
SET show_hidden_columns = true;
SELECT k1, v1,
__DORIS_STREAM_CHANGE_TYPE_COL__,
__DORIS_STREAM_SEQUENCE_COL__
FROM base_stream;
Actual result
k1 v1 __DORIS_STREAM_CHANGE_TYPE_COL__ __DORIS_STREAM_SEQUENCE_COL__
1 NULL UPDATE_BEFORE <sequence>
1 10 UPDATE_AFTER <sequence>
The initial insert followed by delete is consumed by the INSERT INTO tmp_table SELECT * FROM base_stream statement, and the stream offset is advanced before the second insert.
Expected result
The second insert should be returned as one logical APPEND row, because the key is absent from the visible table state after the delete was consumed.
Suspected area
MOW keeps a delete tombstone physically. A subsequent write for that key appears to be classified as ROW_BINLOG_UPDATE instead of ROW_BINLOG_APPEND, after which MIN_DELTA expands it to UPDATE_BEFORE plus UPDATE_AFTER. Relevant code paths include historical_row_retriever.cpp and block_reader.cpp.
Related issues
Description
A direct
MIN_DELTAtable stream on a MOW UNIQUE KEY table emitsUPDATE_BEFOREandUPDATE_AFTERwhen a key is inserted again after its delete event has already been consumed. From the logical table perspective, the second write should be anAPPEND.This reproduces without IVM and without materialized-view complete refresh.
Reproduction
Actual result
The initial insert followed by delete is consumed by the
INSERT INTO tmp_table SELECT * FROM base_streamstatement, and the stream offset is advanced before the second insert.Expected result
The second insert should be returned as one logical
APPENDrow, because the key is absent from the visible table state after the delete was consumed.Suspected area
MOW keeps a delete tombstone physically. A subsequent write for that key appears to be classified as
ROW_BINLOG_UPDATEinstead ofROW_BINLOG_APPEND, after whichMIN_DELTAexpands it toUPDATE_BEFOREplusUPDATE_AFTER. Relevant code paths includehistorical_row_retriever.cppandblock_reader.cpp.Related issues