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


##########
be/src/format_v2/column_mapper.cpp:
##########
@@ -990,6 +990,18 @@ static bool mapping_can_use_file_column_directly(const 
ColumnMapping& mapping) {
     return !needs_complex_rematerialize(mapping);
 }
 
+static FilterConversionType direct_filter_conversion(const ColumnMapping& 
mapping) {
+    DORIS_CHECK(mapping.table_type != nullptr);
+    // FileScanOperator deliberately keeps VARBINARY predicates above external 
readers. Their
+    // physical binary representations are not uniformly supported by 
reader-side expression and
+    // metadata filtering, so localizing a late runtime filter here can 
incorrectly reject rows.
+    if (remove_nullable(mapping.table_type)->get_primitive_type() == 
TYPE_VARBINARY) {
+        return FilterConversionType::FINALIZE_ONLY;

Review Comment:
   This keeps projected VARBINARY filters above the reader, but it breaks 
predicate-only VARBINARY filters. Hidden filter mappings are created after the 
visible `projected_columns` loop, and `FINALIZE_ONLY` makes 
`filter_conversion_has_local_source()` false, so `localize_filters()` skips the 
hidden VARBINARY mapping instead of adding it as a predicate column. It is also 
never added as a non-predicate column, and `TableReader::finalize_chunk()` only 
materializes visible `mappings()`, not hidden mappings. A query that filters on 
a non-projected VARBINARY column therefore reaches the scanner-side fallback 
without the VARBINARY slot in the table block. Please make predicate-only 
VARBINARY filters materialize a column for final evaluation while still 
avoiding reader-local predicate pushdown, and add a regression where the output 
projects a different column and the VARBINARY column appears only in the filter.



##########
be/src/format_v2/parquet/reader/map_column_reader.cpp:
##########
@@ -126,32 +143,50 @@ Status MapColumnReader::build_nested_column(int64_t 
length_upper_bound, MutableC
         }
 
         const bool parent_is_null = def_level < _definition_level - 1;
-        if (parent_is_null && parent_null_map == nullptr) {
+        if (parent_is_null && !_type->is_nullable()) {
             return Status::Corruption("Parquet MAP column {} contains null for 
non-nullable MAP",
                                       _name);
         }
         parent_nulls.push_back(parent_is_null);
         entry_counts.push_back(def_level >= _definition_level ? 1 : 0);
-        ++*values_read;
+        ++*values_processed;
     }
     set_nested_build_level_cursor(level_idx);
 
     uint64_t total_entries = 0;
     for (const auto entry_count : entry_counts) {
         total_entries += entry_count;
     }
-    const size_t key_start = key_column->size();
     int64_t key_value_count = 0;
-    
RETURN_IF_ERROR(_key_reader->build_nested_column(static_cast<int64_t>(total_entries),
-                                                     key_column, 
&key_value_count));
+    size_t key_start = 0;
+    if (column != nullptr) {
+        key_start = key_column->size();
+        
RETURN_IF_ERROR(_key_reader->build_nested_column(static_cast<int64_t>(total_entries),
+                                                         key_column, 
&key_value_count));
+    } else if (auto* scalar_key_reader = 
dynamic_cast<ScalarColumnReader*>(_key_reader.get())) {
+        // MAP keys are required even if a projected Doris key type is 
nullable. Validate each
+        // actual entry directly from the key level stream while advancing 
past empty/null maps.
+        for (const int64_t key_level_idx : map_level_indices) {
+            if (def_levels[key_level_idx] >= _definition_level) {
+                
RETURN_IF_ERROR(scalar_key_reader->validate_nested_value(key_level_idx, true));
+                ++key_value_count;
+            }
+        }
+        scalar_key_reader->set_nested_build_level_cursor(level_idx);
+    } else {
+        
RETURN_IF_ERROR(_key_reader->consume_nested_column(static_cast<int64_t>(total_entries),

Review Comment:
   `consume_nested_column()` is documented to preserve the same null/alignment 
validation as `build_nested_column()`, but this non-scalar key branch only 
checks that the complex key reader consumed the expected count. MAP schemas 
intentionally accept optional key fields for compatibility, and the 
materialized path still rejects actual null keys by checking the appended key 
column. With a nullable STRUCT/LIST MAP key, skipping a row now takes this 
branch; the complex key reader accepts the null key as a valid nullable value 
and returns the expected count, so malformed data is silently accepted whenever 
that row is skipped. Please make the consume-only MAP key path validate that 
every key entry is non-null regardless of key reader kind, and add a skip 
regression for an optional complex key containing a null key.



-- 
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