From 57f1acf54ed619bb6d832e3a1e5112c8679d88f2 Mon Sep 17 00:00:00 2001 From: starocean999 Date: Wed, 20 May 2026 11:06:55 +0800 Subject: [PATCH] [fix](view) Prevent invalid alias rewrite in view definitions (#63353) Creating a view that expands a subquery alias star over an aggregate subquery could persist an invalid inline view definition. During view SQL rewrite, subquery alias output slots inherited the child slot SQL positions, so inner aggregate columns could be rewritten to self-references such as c.pack_factory. Querying the view then failed with Unknown column in AGGREGATE clause. --- .../plans/logical/LogicalSubQueryAlias.java | 7 ++- .../apache/doris/catalog/CreateViewTest.java | 24 ++++++++++ .../bind_view_alias_star_agg.out | 3 ++ .../bind_view_alias_star_agg.groovy | 46 +++++++++++++++++++ 4 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 regression-test/data/nereids_rules_p0/bind_relation/bind_view_alias_star_agg.out create mode 100644 regression-test/suites/nereids_rules_p0/bind_relation/bind_view_alias_star_agg.groovy diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalSubQueryAlias.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalSubQueryAlias.java index 4aff4dda9900f0..e158aaa2b2e49d 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalSubQueryAlias.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalSubQueryAlias.java @@ -121,9 +121,14 @@ private List computeOutputInternal(boolean asteriskOutput) { newQualifier.addAll(qualifier); } + // Subquery alias outputs are synthetic slots. They should keep the aliased + // qualifier/name, but must not reuse the child slot's SQL index. Otherwise + // CREATE VIEW rewrite can map an outer alias-star expansion back onto inner + // aggregate SQL text and persist invalid self-references. Slot qualified = originSlot .withQualifier(newQualifier) - .withName(columnAlias); + .withName(columnAlias) + .withIndexInSql(null); currentOutput.add(qualified); } return currentOutput.build(); diff --git a/fe/fe-core/src/test/java/org/apache/doris/catalog/CreateViewTest.java b/fe/fe-core/src/test/java/org/apache/doris/catalog/CreateViewTest.java index ec17ca18a07e12..450e824de101a1 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/catalog/CreateViewTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/catalog/CreateViewTest.java @@ -212,6 +212,30 @@ public void testAlterView() throws Exception { alter1.getInlineViewDef()); } + @Test + public void testCreateViewWithAliasStarOverAggregateSubquery() throws Exception { + String createViewSql = "create view test.alias_star_agg_view as " + + "with sale2 as (select 1 as pack_factory, 2 as area, 3 as purchase_month, " + + "4 as label_model, 50000 as mile_range), " + + "sale3 as (" + + "select c.*, s.id, s.id * 10000 as mile_range " + + "from (select pack_factory, area, purchase_month, label_model, " + + "max(mile_range) / 10000 as max_range " + + "from sale2 group by pack_factory, area, purchase_month, label_model) c " + + "join (select 1 as id) s where s.id <= max_range) " + + "select * from sale3"; + ExceptionChecker.expectThrowsNoException(() -> createView(createViewSql)); + + Database db = Env.getCurrentInternalCatalog().getDbOrDdlException("test"); + View view = (View) db.getTableOrDdlException("alias_star_agg_view"); + Assert.assertFalse(view.getInlineViewDef().contains("group by c.")); + Assert.assertFalse(view.getInlineViewDef().contains("select c.pack_factory")); + + String explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, + "EXPLAIN select * from test.alias_star_agg_view"); + Assert.assertFalse(explainString.contains("Unknown column")); + } + @Test public void testViewRejectVarbinary() throws Exception { ExceptionChecker.expectThrowsWithMsg( diff --git a/regression-test/data/nereids_rules_p0/bind_relation/bind_view_alias_star_agg.out b/regression-test/data/nereids_rules_p0/bind_relation/bind_view_alias_star_agg.out new file mode 100644 index 00000000000000..ce51f733f423eb --- /dev/null +++ b/regression-test/data/nereids_rules_p0/bind_relation/bind_view_alias_star_agg.out @@ -0,0 +1,3 @@ +-- This file is automatically generated. You should know what you did if you want to edit this +-- !select_view -- +1 2 3 4 5 1 10000 diff --git a/regression-test/suites/nereids_rules_p0/bind_relation/bind_view_alias_star_agg.groovy b/regression-test/suites/nereids_rules_p0/bind_relation/bind_view_alias_star_agg.groovy new file mode 100644 index 00000000000000..68e1b1cf50ad70 --- /dev/null +++ b/regression-test/suites/nereids_rules_p0/bind_relation/bind_view_alias_star_agg.groovy @@ -0,0 +1,46 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +suite("bind_view_alias_star_agg") { + sql "SET enable_nereids_planner=true" + sql "set runtime_filter_mode=OFF" + sql "SET enable_fallback_to_original_planner=false" + + sql "DROP VIEW IF EXISTS v_bind_view_alias_star_agg" + + sql """ + create view v_bind_view_alias_star_agg as + with sale2 as ( + select 1 as pack_factory, 2 as area, 3 as purchase_month, 4 as label_model, 50000 as mile_range + ), + sale3 as ( + select c.*, s.id, s.id * 10000 as mile_range + from ( + select pack_factory, area, purchase_month, label_model, max(mile_range) / 10000 as max_range + from sale2 + group by pack_factory, area, purchase_month, label_model + ) c + join (select 1 as id) s + where s.id <= max_range + ) + select * from sale3 + """ + + order_qt_select_view """ + select * from v_bind_view_alias_star_agg + """ +}