diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/FillUpMissingSlots.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/FillUpMissingSlots.java index 30440b83ffe6ea..6f7dc1de1914a8 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/FillUpMissingSlots.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/FillUpMissingSlots.java @@ -504,11 +504,9 @@ private Plan processWithSortHavingProject(Plan plan, Optional outerScope) } result = oldSort.get().withOrderKeysAndChild(newOrderKeys, result); } - if (!hasAggregateFunc.get()) { - // handle for miss slots case, add a top project - result = new LogicalProject<>(ImmutableList.copyOf(oldProject.getOutput()), result); - } - return result; + // The outputs appended for HAVING and ORDER BY are implementation details. Restore the + // original projection contract after those operators have consumed their helper slots. + return new LogicalProject<>(ImmutableList.copyOf(oldProject.getOutput()), result); } private void collectNotExistsSlotAndAggFunc(Expression expression, Set oldProjectSlots, diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/analysis/FillUpMissingSlotsTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/analysis/FillUpMissingSlotsTest.java index d3fab2e4856c31..1baf69c0555b3b 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/analysis/FillUpMissingSlotsTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/analysis/FillUpMissingSlotsTest.java @@ -319,6 +319,24 @@ public void testHavingAggregateFunction() { ).when(FieldChecker.check("projects", Lists.newArrayList(a1.toSlot())))); } + @Test + void testHavingAggregateFunctionDoesNotLeakHelperOutput() { + Plan plan = PlanChecker.from(connectContext) + .analyze("SELECT 1 FROM t1 HAVING SUM(a1) > 0") + .getPlan(); + Assertions.assertEquals(1, plan.getOutput().size()); + + PlanChecker.from(connectContext) + .analyze("SELECT (SELECT 1 FROM t1 HAVING SUM(a1) > 0)"); + + ExceptionChecker.expectThrowsWithMsg( + AnalysisException.class, + "Multiple columns returned by subquery are not yet supported. Found 2", + () -> PlanChecker.from(connectContext).analyze( + "SELECT (SELECT 1, 2 FROM t1 HAVING SUM(a1) > 0)" + )); + } + @Test void testJoinWithHaving() { String sql = "SELECT a1, sum(a2) FROM t1, t2 WHERE t1.pk = t2.pk GROUP BY a1 HAVING a1 > sum(b1)"; diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/analysis/NormalizeAggregateTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/analysis/NormalizeAggregateTest.java index 37aa9d4913a33a..d65c8b82129e67 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/analysis/NormalizeAggregateTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/analysis/NormalizeAggregateTest.java @@ -492,31 +492,36 @@ void testAggFunctionNullabe2() { .analyze("select 1 from t1 having sum(id) > 10") .matchesFromRoot( logicalResultSink( - logicalFilter( - logicalProject( + logicalProject( + logicalFilter( logicalProject( - logicalAggregate().when(agg -> { - List output = agg.getOutput(); - checkExprsToSql(output, "sum(id)"); - Assertions.assertTrue(output.get(0).nullable()); + logicalProject( + logicalAggregate().when(agg -> { + List output = agg.getOutput(); + checkExprsToSql(output, "sum(id)"); + Assertions.assertTrue(output.get(0).nullable()); + return true; + }) + ).when(project -> { + List projects = project.getProjects(); + checkExprsToSql(projects, "sum(id)"); + Assertions.assertTrue(projects.get(0).nullable()); return true; }) ).when(project -> { List projects = project.getProjects(); - checkExprsToSql(projects, "sum(id)"); - Assertions.assertTrue(projects.get(0).nullable()); + checkExprsToSql(projects, "1 AS `1`", "sum(id)"); + Assertions.assertTrue(projects.get(1).nullable()); return true; }) - ).when(project -> { - List projects = project.getProjects(); - checkExprsToSql(projects, "1 AS `1`", "sum(id)"); - Assertions.assertTrue(projects.get(1).nullable()); + ).when(filter -> { + List conjuncts = filter.getExpressions(); + checkExprsToSql(conjuncts, "(sum(id) > 10)"); + Assertions.assertTrue(conjuncts.get(0).child(0).nullable()); return true; }) - ).when(filter -> { - List conjuncts = filter.getExpressions(); - checkExprsToSql(conjuncts, "(sum(id) > 10)"); - Assertions.assertTrue(conjuncts.get(0).child(0).nullable()); + ).when(project -> { + checkExprsToSql(project.getProjects(), "1"); return true; }) ) diff --git a/regression-test/data/nereids_rules_p0/fill_up_missing_slots/test_having_with_aggregate_function.out b/regression-test/data/nereids_rules_p0/fill_up_missing_slots/test_having_with_aggregate_function.out index fcf06b6b3bffa3..64fd7bfad76ca1 100644 --- a/regression-test/data/nereids_rules_p0/fill_up_missing_slots/test_having_with_aggregate_function.out +++ b/regression-test/data/nereids_rules_p0/fill_up_missing_slots/test_having_with_aggregate_function.out @@ -10,3 +10,8 @@ -- !having_array_lambda_local_slots -- 1 2 +-- !scalar_subquery_having_true -- +1 + +-- !scalar_subquery_having_false -- + diff --git a/regression-test/suites/nereids_rules_p0/fill_up_missing_slots/test_having_with_aggregate_function.groovy b/regression-test/suites/nereids_rules_p0/fill_up_missing_slots/test_having_with_aggregate_function.groovy index 04a2ec51039ebd..2cd7d0e8484ed8 100644 --- a/regression-test/suites/nereids_rules_p0/fill_up_missing_slots/test_having_with_aggregate_function.groovy +++ b/regression-test/suites/nereids_rules_p0/fill_up_missing_slots/test_having_with_aggregate_function.groovy @@ -68,4 +68,19 @@ suite("test_having_project") { sql "SELECT 1 AS c1 FROM t HAVING count(1) > 0 OR c1 IS NOT NULL" exception "HAVING expression 'c1' must appear in the GROUP BY clause or be used in an aggregate function" } + + sql "INSERT INTO t VALUES (1)" + + qt_scalar_subquery_having_true """ + SELECT (SELECT 1 FROM t HAVING SUM(id) > 0) AS scalar_value + """ + + qt_scalar_subquery_having_false """ + SELECT (SELECT 1 FROM t HAVING SUM(id) < 0) AS scalar_value + """ + + test { + sql "SELECT (SELECT 1, 2 FROM t HAVING SUM(id) > 0)" + exception "Multiple columns returned by subquery are not yet supported. Found 2" + } }