This is an automated email from the ASF dual-hosted git repository.

924060929 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/master by this push:
     new a4c062c6a86 [fix](meta path) Preserve metadata access path type for 
map_entries (#68040)
a4c062c6a86 is described below

commit a4c062c6a86a3ff9dc4594817804964ded4288bd
Author: linrrarity <[email protected]>
AuthorDate: Thu Sep 17 11:33:29 2026 +0800

    [fix](meta path) Preserve metadata access path type for map_entries (#68040)
    
    ### What problem does this PR solve?
    
    When `transform_values` operates on physical nested Map columns with
    nested-column pruning enabled:
    
    - `MAP<..., ARRAY<...>>` may fail because `VALUES.OFFSET` is incorrectly
    marked as a DATA access path.
    - `MAP<..., STRUCT<...>>` may crash the BE because `VALUES.NULL` is
    incorrectly treated as a Struct data field, causing all physical Struct
    child iterators to be pruned.
    
    ### Root cause
    
    `AccessPathExpressionCollector.visitMapEntries` creates a new
    `CollectorContext` while translating access paths from `map_entries`.
    
    The new context did not inherit the original `ColumnAccessPathType`, so
    META paths such as `OFFSET` and `NULL` fell back to the default DATA
    type.
    
    ### What is changed?
    
    Propagate the original access-path type to the new context in
    `visitMapEntries`.
    
    Added regression coverage for:
    
    - `transform_values((k, v) -> size(v), map<int, array<int>>)`
    - `transform_values((k, v) -> v is null, map<int, struct<...>>)`
    
    The tests verify that `VALUES.OFFSET` and `VALUES.NULL` remain META
    access paths.
---
 .../rewrite/AccessPathExpressionCollector.java     |  1 +
 .../rules/rewrite/PruneNestedColumnTest.java       | 20 +++++++++++++++++++
 .../map_functions/test_map_lambda.out              | 10 ++++++++++
 .../map_functions/test_map_lambda.groovy           | 23 ++++++++++++++++++----
 4 files changed, 50 insertions(+), 4 deletions(-)

diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/AccessPathExpressionCollector.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/AccessPathExpressionCollector.java
index 134e4783a7a..cfd22ee5eea 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/AccessPathExpressionCollector.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/AccessPathExpressionCollector.java
@@ -466,6 +466,7 @@ public class AccessPathExpressionCollector extends 
DefaultExpressionVisitor<Void
                 mapContext.accessPathBuilder.accessPath.addAll(path.subList(2, 
path.size()));
                 
mapContext.accessPathBuilder.addPrefix("key".equalsIgnoreCase(entryField)
                         ? AccessPathInfo.ACCESS_MAP_KEYS : 
AccessPathInfo.ACCESS_MAP_VALUES);
+                mapContext.setType(context.type);
                 return continueCollectAccessPath(mapEntries.getArgument(0), 
mapContext);
             }
         }
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/PruneNestedColumnTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/PruneNestedColumnTest.java
index 6814b523a43..17d59219a34 100644
--- 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/PruneNestedColumnTest.java
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/PruneNestedColumnTest.java
@@ -258,6 +258,26 @@ public class PruneNestedColumnTest extends 
TestWithFeService implements MemoPatt
                 ImmutableList.of());
     }
 
+    @Test
+    public void testTransformValuesPreservesValueOffsetMetaPath() throws 
Exception {
+        assertAllAccessPathsContain(
+                "select transform_values((k, v) -> size(v), map_arr_col) from 
map_array_tbl",
+                ImmutableList.of(
+                        path("map_arr_col", "KEYS"),
+                        metaPath("map_arr_col", "VALUES", "OFFSET")),
+                ImmutableList.of(path("map_arr_col", "VALUES", "OFFSET")));
+    }
+
+    @Test
+    public void testTransformValuesPreservesValueNullMetaPath() throws 
Exception {
+        assertAllAccessPathsContain(
+                "select transform_values((k, v) -> v is null, element_at(s, 
'data')[1]) from tbl",
+                ImmutableList.of(
+                        path("s", "data", "*", "KEYS"),
+                        metaPath("s", "data", "*", "VALUES", "NULL")),
+                ImmutableList.of(path("s", "data", "*", "VALUES", "NULL")));
+    }
+
     @Test
     public void testFullFieldAccessKeepsExactMetadataPath() throws Exception {
         assertColumn("select element_at(s, 'city') from tbl "
diff --git 
a/regression-test/data/query_p0/sql_functions/map_functions/test_map_lambda.out 
b/regression-test/data/query_p0/sql_functions/map_functions/test_map_lambda.out
index 8bdd1713035..f18d3c83b09 100644
--- 
a/regression-test/data/query_p0/sql_functions/map_functions/test_map_lambda.out
+++ 
b/regression-test/data/query_p0/sql_functions/map_functions/test_map_lambda.out
@@ -53,6 +53,16 @@ x:a  y:b
 -- !transform_values_array --
 [10, 1]        [20, 21, 2]
 
+-- !transform_values_array_size --
+1      {1:1, 2:2}
+2      {}
+3      \N
+
+-- !transform_values_struct_is_null --
+1      {1:0, 2:1}
+2      {}
+3      \N
+
 -- !nested_array_lambda --
 {1:[21], 2:[32, 33]}
 
diff --git 
a/regression-test/suites/query_p0/sql_functions/map_functions/test_map_lambda.groovy
 
b/regression-test/suites/query_p0/sql_functions/map_functions/test_map_lambda.groovy
index 9d0266da3df..fb7a0ac001e 100644
--- 
a/regression-test/suites/query_p0/sql_functions/map_functions/test_map_lambda.groovy
+++ 
b/regression-test/suites/query_p0/sql_functions/map_functions/test_map_lambda.groovy
@@ -18,6 +18,7 @@
 suite("test_map_lambda", "p0") {
     sql "set enable_nereids_planner = true"
     sql "set enable_fallback_to_original_planner = false"
+    sql "set enable_prune_nested_column = true"
     sql "drop table if exists test_map_lambda"
     sql """
         create table test_map_lambda (
@@ -26,7 +27,8 @@ suite("test_map_lambda", "p0") {
             mii map<int, int>,
             mss map<string, string>,
             mia map<int, array<int>>,
-            mim map<int, map<int, int>>
+            mim map<int, map<int, int>>,
+            mis map<int, struct<n:int, s:string>>
         )
         duplicate key(id)
         distributed by hash(id) buckets 1
@@ -38,13 +40,16 @@ suite("test_map_lambda", "p0") {
              map(1, 10, 2, 20),
              map('a', 'x', 'b', 'y'),
              map(1, [10], 2, [20, 21]),
-             map(1, map(2, 20), 3, map(4, 40))),
+             map(1, map(2, 20), 3, map(4, 40)),
+             map(1, named_struct('n', 10, 's', 'x'),
+                 2, cast(null as struct<n:int, s:string>))),
             (2, 0,
              cast(map() as map<int, int>),
              cast(map() as map<string, string>),
              cast(map() as map<int, array<int>>),
-             cast(map() as map<int, map<int, int>>)),
-            (3, 0, null, null, null, null)
+             cast(map() as map<int, map<int, int>>),
+             cast(map() as map<int, struct<n:int, s:string>>)),
+            (3, 0, null, null, null, null, null)
     """
 
     qt_map_apply """
@@ -170,6 +175,16 @@ suite("test_map_lambda", "p0") {
             from test_map_lambda where id = 1
         ) t
     """
+    order_qt_transform_values_array_size """
+        select id, transform_values((k, v) -> size(v), mia)
+        from test_map_lambda
+        order by id
+    """
+    order_qt_transform_values_struct_is_null """
+        select id, transform_values((k, v) -> v is null, mis)
+        from test_map_lambda
+        order by id
+    """
     qt_nested_array_lambda """
         select map_apply(
             (k, vals) -> struct(


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

Reply via email to