This is an automated email from the ASF dual-hosted git repository. englefly pushed a commit to branch lazy-mat-nest in repository https://gitbox.apache.org/repos/asf/doris.git
commit a6f9d551df902409311d288efa0a56d6cbb1ac39 Author: englefly <[email protected]> AuthorDate: Thu May 28 14:38:23 2026 +0800 [fix](fe) preserve user-visible column order in TopN lazy mat final projection The final PhysicalProject above Materialize appended all pulled-up expressions at the end regardless of their original position in userVisibleOutput. When a nested expression (struct_element, element_at, etc.) was not the last SELECT column, the result schema was swapped. Fix by building outputExprs in userVisibleOutput order, replacing each pulled-up slot in-place with its corresponding expression via pulledUpExprMap, so output columns match the SQL SELECT order. Add regression tests (struct/variant/map nested expr before id). Co-Authored-By: Claude Opus 4.7 <[email protected]> --- .../post/materialize/LazyMaterializeTopN.java | 10 +++- .../topn_lazy_nested_column_pruning.groovy | 61 ++++++++++++++++++++++ 2 files changed, 69 insertions(+), 2 deletions(-) diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/processor/post/materialize/LazyMaterializeTopN.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/processor/post/materialize/LazyMaterializeTopN.java index 2d70bd9cdf2..b1cf86793bd 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/processor/post/materialize/LazyMaterializeTopN.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/processor/post/materialize/LazyMaterializeTopN.java @@ -145,13 +145,19 @@ public class LazyMaterializeTopN extends PlanPostProcessor { if (pulledUpExprs.isEmpty()) { result = new PhysicalProject(ImmutableList.copyOf(userVisibleOutput), null, result); } else { + Map<ExprId, NamedExpression> pulledUpExprMap = new HashMap<>(); + for (NamedExpression ne : pulledUpExprs) { + pulledUpExprMap.put(ne.getExprId(), ne); + } List<NamedExpression> outputExprs = new ArrayList<>(); for (Slot slot : userVisibleOutput) { - if (!pulledUpExprIds.contains(slot.getExprId())) { + NamedExpression pulledUpExpr = pulledUpExprMap.get(slot.getExprId()); + if (pulledUpExpr != null) { + outputExprs.add(pulledUpExpr); + } else { outputExprs.add(slot); } } - outputExprs.addAll(pulledUpExprs); result = new PhysicalProject(ImmutableList.copyOf(outputExprs), null, result); } return result; diff --git a/regression-test/suites/nereids_rules_p0/column_pruning/topn_lazy_nested_column_pruning.groovy b/regression-test/suites/nereids_rules_p0/column_pruning/topn_lazy_nested_column_pruning.groovy index c0141215758..6246fc7819c 100644 --- a/regression-test/suites/nereids_rules_p0/column_pruning/topn_lazy_nested_column_pruning.groovy +++ b/regression-test/suites/nereids_rules_p0/column_pruning/topn_lazy_nested_column_pruning.groovy @@ -278,4 +278,65 @@ suite("topn_lazy_nested_column_pruning") { limit 3 """ sql """ set topn_lazy_materialization_using_index = false; """ + + // ============================================= + // Test 15: STRUCT nested expr BEFORE id — verify column order preserved + // SELECT city_expr, id should produce [city, id] not [id, city] + // ============================================= + explain { + sql """ + select substring(struct_element(struct_col, 'city'), 1) as city, id + from ncp_tbl + order by id + limit 3 + """ + contains("VMaterializeNode") + contains("row_ids: [__DORIS_GLOBAL_ROWID_COL__ncp_tbl]") + } + qt_struct_col_order_result """ + select substring(struct_element(struct_col, 'city'), 1) as city, id + from ncp_tbl + order by id + limit 3 + """ + + // ============================================= + // Test 16: VARIANT nested expr BEFORE id — verify column order preserved + // ============================================= + explain { + sql """ + select substring(element_at(payload, 'name'), 1) as name, id, s + from vt + order by id + limit 3 + """ + contains("VMaterializeNode") + contains("row_ids: [__DORIS_GLOBAL_ROWID_COL__vt]") + } + qt_variant_col_order_result """ + select substring(element_at(payload, 'name'), 1) as name, id, s + from vt + order by id + limit 3 + """ + + // ============================================= + // Test 17: MAP nested expr BEFORE id — verify column order preserved + // ============================================= + explain { + sql """ + select element_at(map_col, 'a') as val, id + from ncp_tbl + order by id + limit 3 + """ + contains("VMaterializeNode") + contains("row_ids: [__DORIS_GLOBAL_ROWID_COL__ncp_tbl]") + } + qt_map_col_order_result """ + select element_at(map_col, 'a') as val, id + from ncp_tbl + order by id + limit 3 + """ } --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
