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


##########
be/src/format_v2/parquet/parquet_reader.cpp:
##########
@@ -74,104 +74,149 @@ const ParquetColumnSchema* schema_child_by_name(const 
ParquetColumnSchema& schem
     return child_it == schema.children.end() ? nullptr : child_it->get();
 }
 
-bool collect_variant_residual_leaf_ids(const ParquetColumnSchema& schema,
-                                       const format::LocalColumnIndex& 
projection,
-                                       std::vector<int>* residual_leaf_ids) {
+bool collect_variant_terminal_fallback_leaf_ids(const ParquetColumnSchema& 
schema,
+                                                const 
format::LocalColumnIndex& projection,
+                                                std::vector<int>* 
residual_leaf_ids) {
     DORIS_CHECK(residual_leaf_ids != nullptr);
     const auto* value = schema_child_by_name(schema, "value");
     const auto* typed_value = schema_child_by_name(schema, "typed_value");
-    if (value != nullptr && typed_value != nullptr) {
-        if (value->kind != ParquetColumnSchemaKind::PRIMITIVE || 
value->leaf_column_id < 0) {
+    if (value != nullptr && value->kind == ParquetColumnSchemaKind::PRIMITIVE 
&&
+        typed_value != nullptr) {
+        if (value->leaf_column_id < 0) {
             return false;
         }
+        const auto typed_projection_it =
+                std::ranges::find_if(projection.children, [&](const auto& 
child_projection) {
+                    return child_projection.local_id() == 
typed_value->local_id;
+                });
+        if (typed_projection_it == projection.children.end()) {
+            return false;
+        }
+        if (typed_value->kind != ParquetColumnSchemaKind::PRIMITIVE) {
+            return collect_variant_terminal_fallback_leaf_ids(*typed_value, 
*typed_projection_it,

Review Comment:
   [P1] Preserve legacy generator plans during rolling upgrades
   
   Skipping the ancestor `value` here relies on the new FE container-preserving 
access paths, but an upgraded BE still accepts plans from the pre-PR FE:
   
   ```text
   Project(x['k'])
     Generate(explode(v) AS x)
       FileScan(v)
   ```
   
   That FE sends `[v,k]` for `SELECT x['k'] FROM t LATERAL VIEW explode(v) e AS 
x`. With a conforming shredded Parquet schema containing object field `k`, a 
row can store `v = [{"k":1}]` in the root residual while `k.value` is all NULL. 
The new guard therefore retains a partial `v` and omits the array. 
`VExplodeV2TableFunction::_process_init_variant` then calls 
`cast_variant_to_array(nullptr, ...)`, whose `get_value_ref()` throws "A 
projected Parquet Variant can only serve its validated shredded leaves" instead 
of returning `1`. The previous ancestor check restored full `v`.
   
   Both sides still accept execution version 17, and scanner selection does not 
negotiate this new path contract. Keep the conservative ancestor check for 
legacy requests, or gate terminal-only projection on an explicit producer 
capability, and cover this old-FE request in a compatibility test. This remains 
distinct from thread 4256992660: that current-FE variadic fix cannot protect an 
older FE's unary plan during BE-first upgrade.



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