github-actions[bot] commented on code in PR #65502:
URL: https://github.com/apache/doris/pull/65502#discussion_r3568056550


##########
be/src/format_v2/table/iceberg_reader.cpp:
##########
@@ -438,38 +482,125 @@ Status 
IcebergTableReader::_append_row_position_output_column(format::FileScanRe
     return Status::OK();
 }
 
+const format::ColumnDefinition* 
IcebergTableReader::_find_equality_delete_data_field(
+        const EqualityDeleteFilter& filter, size_t key_idx) const {
+    DORIS_CHECK(key_idx < filter.field_ids.size());
+    DORIS_CHECK(key_idx < filter.field_names.size());
+    const int field_id = filter.field_ids[key_idx];
+    auto field_it = std::ranges::find_if(_data_reader.file_schema,
+                                         [field_id](const 
format::ColumnDefinition& field) {
+                                             return 
field.has_identifier_field_id() &&
+                                                    
field.get_identifier_field_id() == field_id;
+                                         });
+    if (field_it != _data_reader.file_schema.end() ||

Review Comment:
   This still lets a partial-id migrated file bypass BY_NAME binding. 
`mapping_mode()` intentionally switches the split to BY_NAME when any data 
column lacks an Iceberg field id, so normal scan columns are resolved by 
`ColumnMapper`'s name/identifier/alias rules. This helper, however, first 
accepts any file column whose field id equals the equality key id and returns 
before it checks the mode. If an imported file has the real key column matched 
only by `name_mapping` and some other physical column carrying the stale key 
id, the delete predicate compares against that unrelated column and misses or 
misapplies equality deletes. Please skip the id fast path when `mapping_mode() 
== BY_NAME` and resolve hidden equality keys through the same BY_NAME matcher 
as normal materialization.



##########
fe/fe-core/src/main/java/org/apache/doris/datasource/iceberg/IcebergUtils.java:
##########
@@ -1198,6 +1204,27 @@ public static List<Column> parseSchema(Schema schema, 
boolean enableMappingVarbi
         return resSchema;
     }
 
+    private static String 
serializeInitialDefault(org.apache.iceberg.types.Type type, Object value,
+            boolean enableMappingVarbinary) {
+        String humanValue = Transforms.identity(type).toHumanString(type, 
value);
+        if (type.typeId() == TypeID.TIMESTAMP) {
+            // Iceberg formats timestamps as ISO-8601 (for example 
2024-01-01T00:00:00), while
+            // Doris' DATETIMEV2 default parser requires a space between the 
date and time.
+            return humanValue.replace('T', ' ');
+        }
+        if (enableMappingVarbinary && type.typeId() == TypeID.UUID) {
+            // BINARY and FIXED are already Base64 in Iceberg's human 
representation. UUID uses
+            // canonical text, so encode its 16-byte Iceberg representation 
explicitly to keep the
+            // VARBINARY carrier consistent for all three mapped types.
+            UUID uuid = (UUID) value;
+            ByteBuffer bytes = ByteBuffer.allocate(16);
+            bytes.putLong(uuid.getMostSignificantBits());
+            bytes.putLong(uuid.getLeastSignificantBits());
+            return Base64.getEncoder().encodeToString(bytes.array());
+        }
+        return humanValue;

Review Comment:
   This still sends the wrong representation for binary-like defaults when 
varbinary mapping is disabled. In that mode UUID/BINARY become Doris STRING and 
FIXED becomes CHAR, so the BE branch that Base64-decodes `TYPE_VARBINARY` never 
runs; the STRING/CHAR serde keeps this `humanValue` text as-is. Equality delete 
files, however, read BYTE_ARRAY/FIXED_LEN_BYTE_ARRAY keys as raw bytes into 
string columns. For example an added BINARY default `00 01 02 ff` is carried as 
`"AAEC/w=="`, but the delete key column contains raw bytes, so the missing-key 
literal does not match the delete row. Please normalize UUID/BINARY/FIXED 
defaults to the same raw-byte representation for the STRING/CHAR mapping as 
well, or carry enough type metadata for BE to decode them before building the 
literal.



##########
be/src/format/table/iceberg_reader.cpp:
##########
@@ -553,6 +559,11 @@ Status 
IcebergOrcReader::on_before_init_reader(ReaderInitContext* ctx) {
         if (i < _expand_columns.size()) {
             _expand_columns[i].name = table_col_name;
         }
+        if (it == field_id_to_file_col_name.end()) {

Review Comment:
   This missing-key branch registers a constant for the equality key, but the 
ORC path still treats the same synthetic column as physically present. After 
this branch runs, the loop still appends `table_col_name` to 
`ctx->column_names` and `add_children()` marks it with `exists=true`. ORC 
therefore does not put it in `_fill_missing_cols`; 
`_init_file_column_mapping()` adds it to `_read_file_cols`, and the batch read 
later returns `Wrong read column` because the old ORC file has no such physical 
column. Please leave the hidden equality key in the 
block/default-materialization path without marking it as an existing ORC child, 
and add an end-to-end V1 ORC missing-key equality-delete test.



##########
be/src/format_v2/table/iceberg_reader.cpp:
##########
@@ -632,12 +791,36 @@ Status 
IcebergTableReader::_read_equality_delete_file(const TIcebergDeleteFileDe
             return Status::NotSupported(
                     "Iceberg equality delete does not support complex column 
{}", field_it->name);
         }
-        delete_fields.push_back(*field_it);
-        delete_field_ids.push_back(field_id);
-        delete_key_types.push_back(field_it->type);
+        delete_fields->push_back(*field_it);
+        result->field_ids.push_back(field_id);
+        result->field_names.push_back(field_it->name);
+        result->key_types.push_back(field_it->type);
     }
+    return Status::OK();
+}
+
+Status IcebergTableReader::_load_equality_delete_file(const 
TIcebergDeleteFileDesc& delete_file,
+                                                      const 
TFileScanRangeParams& scan_params,
+                                                      
IcebergDeleteFileIOContext* delete_io_ctx,
+                                                      EqualityDeleteFilter* 
result) {
+    DORIS_CHECK(result != nullptr);
+    std::unique_ptr<format::FileReader> reader;
+    RETURN_IF_ERROR(_create_delete_file_reader(delete_file, scan_params, 
delete_io_ctx, &reader));

Review Comment:
   The reader created here needs the same TIMESTAMPTZ mapping as the data 
reader. Normal `TableReader` construction passes `enable_mapping_timestamp_tz` 
into Parquet/ORC readers, but `_create_delete_file_reader()` uses those 
constructors' default `false`, so adjusted-UTC timestamp keys in 
equality-delete files are loaded as DATETIMEV2. The data side may still be 
TIMESTAMPTZ and then gets cast to the delete key type through the session 
timezone before `_equal()` compares raw column values. Around a DST fold, two 
different instants can collapse to the same local DATETIMEV2 and an equality 
delete for one instant can delete rows for the other. Please pass the effective 
timestamp-tz mapping flag into V2 delete-file readers and add equality-delete 
coverage with `enable_mapping_timestamp_tz=true` in a non-UTC timezone.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to