Skip to content

Commit 86eedb4

Browse files
eldenmoonYour Name
authored andcommitted
[fix](variant) fix array subscript on pruned variant subpath (#63891)
### What problem does this PR solve? Fix variant subpath pruning for projections where the top-level expression is an array subscript or `element_at` over a variant subpath. The planner could leave the outer subscript on the original variant access chain after pruning, which made valid 1-based array subscripts return `NULL`. The original array-of-objects repro depends on nested-group variant semantics, so the regression in this PR uses a plain `VARIANT` array leaf without nested group. Since that query result is already correct on current master, the regression asserts the verbose plan instead: the scan uses `subColPath=[items, type]` and the final array subscript is applied to the pruned variant slot. ### Check List - [x] Added regression test - [x] Added FE planner unit test ### Tests - `./run-regression-test.sh --run --conf tmp/regression-conf.auto.groovy -d variant_p0 -s test_variant_array_subscript` - `./run-fe-ut.sh --run org.apache.doris.nereids.rules.rewrite.VariantPruningLogicTest` passed earlier on the same FE code; rerun after this regression-only amend was blocked by system pid/thread exhaustion before test execution.
1 parent ce53a3e commit 86eedb4

3 files changed

Lines changed: 74 additions & 1 deletion

File tree

fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/VariantSubPathPruning.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -386,7 +386,8 @@ public Plan visitLogicalProject(LogicalProject<? extends Plan> project, Context
386386
.withChildren(context.elementAtToSlotMap.get(child));
387387
} else {
388388
addOthers = false;
389-
newProjection = projection;
389+
newProjection = (NamedExpression) projection
390+
.withChildren(ExpressionUtils.replace(child, context.elementAtToSlotMap));
390391

391392
// try push element_at on this slot
392393
if (extractSlotToSubPathPair((ElementAt) child) == null) {

fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/VariantPruningLogicTest.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,24 @@ public void testVariantNumericIndexSubPath() throws Exception {
7070
);
7171
}
7272

73+
@Test
74+
public void testVariantArraySubscriptUsesPrunedSubPath() throws Exception {
75+
String sql = "select cast(v['items']['type'] as array<string>)[1] from variant_tbl";
76+
String explain = getSQLPlanOrErrorMsg(sql, true);
77+
Assertions.assertTrue(explain.contains("final projections: element_at(CAST(v AS array<text>), 1)"),
78+
explain);
79+
Assertions.assertTrue(explain.contains("subColPath=[items, type]"),
80+
explain);
81+
Assertions.assertFalse(explain.contains("element_at(CAST(element_at(element_at("),
82+
explain);
83+
assertVariantSubColumnSlots(
84+
sql,
85+
ImmutableList.of(
86+
ImmutableList.of("items", "type")
87+
)
88+
);
89+
}
90+
7391
@Test
7492
public void testVariantOrPredicatePaths() throws Exception {
7593
assertPredicateAccessPathsEqual(
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
suite("test_variant_array_subscript", "p0") {
19+
sql "set enable_nereids_planner = true"
20+
sql "set enable_fallback_to_original_planner = false"
21+
sql "set default_variant_enable_nested_group = false"
22+
sql "set default_variant_max_subcolumns_count = 100"
23+
24+
sql "DROP TABLE IF EXISTS test_variant_array_subscript"
25+
sql """
26+
CREATE TABLE test_variant_array_subscript (
27+
id BIGINT,
28+
v VARIANT
29+
) ENGINE=OLAP
30+
DUPLICATE KEY(id)
31+
DISTRIBUTED BY HASH(id) BUCKETS 1
32+
PROPERTIES (
33+
"replication_allocation" = "tag.location.default: 1",
34+
"disable_auto_compaction" = "true"
35+
)
36+
"""
37+
38+
sql """
39+
INSERT INTO test_variant_array_subscript VALUES
40+
(1, '{"items":{"type":["e2e_QC","platform_QC"]}}')
41+
"""
42+
sql "sync"
43+
44+
explain {
45+
verbose true
46+
sql """
47+
SELECT CAST(v['items']['type'] AS ARRAY<STRING>)[1]
48+
FROM test_variant_array_subscript
49+
"""
50+
contains "subColPath=[items, type]"
51+
contains "element_at(CAST(v"
52+
notContains "element_at(CAST(element_at(element_at("
53+
}
54+
}

0 commit comments

Comments
 (0)