Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import org.apache.doris.nereids.rules.Rule;
import org.apache.doris.nereids.rules.RuleType;
import org.apache.doris.nereids.trees.expressions.Alias;
import org.apache.doris.nereids.trees.expressions.ArrayItemReference.ArrayItemSlot;
import org.apache.doris.nereids.trees.expressions.Expression;
import org.apache.doris.nereids.trees.expressions.NamedExpression;
import org.apache.doris.nereids.trees.expressions.Slot;
Expand Down Expand Up @@ -207,6 +208,11 @@ static class Resolver {
}

public void resolve(Expression expression, ResolvePlanType planType) {
// ArrayItemSlot represents a lambda-local variable, not an input from the aggregate's child.
// It is bound by its ArrayItemReference and should not participate in GROUP BY validation.
if (expression instanceof ArrayItemSlot) {
return;
}
Pair<Optional<Expression>, Boolean> result = lookUp(expression);
Optional<Expression> found = result.first;
boolean isFoundInOutputExpressions = result.second;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,27 @@ void testJoinWithHaving() {
).when(FieldChecker.check("projects", Lists.newArrayList(a1.toSlot(), sumA2.toSlot()))));
}

@Test
void testHavingLambdaLocalSlots() {
String mapSql = "SELECT a1, COUNT(*) AS n FROM t1 GROUP BY a1 "
+ "HAVING map_exists((k, v) -> v > 1, map(1, COUNT(*)))";
Assertions.assertNotNull(PlanChecker.from(connectContext).analyze(mapSql).getPlan());

String arraySql = "SELECT a1, COUNT(*) AS n FROM t1 GROUP BY a1 "
+ "HAVING array_match_any(array_map(x -> x > 1, array(COUNT(*))))";
Assertions.assertNotNull(PlanChecker.from(connectContext).analyze(arraySql).getPlan());

ExceptionChecker.expectThrowsWithMsg(
AnalysisException.class,
"HAVING expression 'a2' must appear in the GROUP BY clause"
+ " or be used in an aggregate function.",
() -> PlanChecker.from(connectContext).analyze(
"SELECT a1, COUNT(*) AS n FROM t1 GROUP BY a1 "
+ "HAVING array_match_any(array_map(x -> x > 1, "
+ "array(COUNT(*) + a2)))"
));
}

@Test
void testInvalidHaving() {
ExceptionChecker.expectThrowsWithMsg(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,9 @@

-- !having_project_2 --

-- !having_map_lambda_local_slots --
1 2

-- !having_array_lambda_local_slots --
1 2

Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,36 @@ suite("test_having_project") {
SELECT 1 AS c1 FROM t HAVING count(1) > 0
"""

qt_having_map_lambda_local_slots """
SELECT id, COUNT(*) AS n
FROM (SELECT 1 id UNION ALL SELECT 1 id) input
GROUP BY id
HAVING map_exists((k, v) -> v > 1, map(1, COUNT(*)))
ORDER BY id
"""

qt_having_array_lambda_local_slots """
SELECT id, COUNT(*) AS n
FROM (SELECT 1 id UNION ALL SELECT 1 id) input
GROUP BY id
HAVING array_match_any(array_map(x -> x > 1, array(COUNT(*))))
ORDER BY id
"""

test {
sql """
SELECT id, COUNT(*) AS n
FROM (
SELECT 1 id, 1 AS ungrouped_col
UNION ALL
SELECT 1 id, 2 AS ungrouped_col
) input
GROUP BY id
HAVING array_match_any(array_map(x -> x > 1, array(COUNT(*) + ungrouped_col)))
"""
exception "HAVING expression 'ungrouped_col' must appear in the GROUP BY clause or be used in an aggregate function"
}

test {
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"
Expand Down
Loading