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]