Skip to content

Commit dd42a33

Browse files
authored
SQL: Enhance error message on filtering check against aggs (#68763) (#68803)
* Enhance error msg on filtering check against aggs Distinguish between the case where the filtering is a WHERE with aggs appart from a HAVING with missing aggs. (cherry picked from commit ab26062)
1 parent 861944e commit dd42a33

File tree

2 files changed

+31
-5
lines changed

2 files changed

+31
-5
lines changed

x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/analysis/analyzer/Verifier.java

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -391,9 +391,9 @@ private static boolean checkGroupByHaving(LogicalPlan p, Set<Failure> localFailu
391391
Expressions.names(unsupported)));
392392
groupingFailures.add(a);
393393
return false;
394+
}
394395
}
395396
}
396-
}
397397
return true;
398398
}
399399

@@ -662,11 +662,20 @@ private static void checkGroupingFunctionTarget(GroupingFunction f, Set<Failure>
662662
private static void checkFilterOnAggs(LogicalPlan p, Set<Failure> localFailures, AttributeMap<Expression> attributeRefs) {
663663
if (p instanceof Filter) {
664664
Filter filter = (Filter) p;
665-
if ((filter.child() instanceof Aggregate) == false) {
665+
LogicalPlan filterChild = filter.child();
666+
if (filterChild instanceof Aggregate == false) {
666667
filter.condition().forEachDown(Expression.class, e -> {
667668
if (Functions.isAggregate(attributeRefs.getOrDefault(e, e))) {
668-
localFailures.add(
669-
fail(e, "Cannot use WHERE filtering on aggregate function [{}], use HAVING instead", Expressions.name(e)));
669+
if (filterChild instanceof Project) {
670+
filter.condition().forEachDown(FieldAttribute.class,
671+
f -> localFailures.add(fail(e, "[{}] field must appear in the GROUP BY clause or in an aggregate function",
672+
Expressions.name(f)))
673+
);
674+
} else {
675+
localFailures.add(fail(e, "Cannot use WHERE filtering on aggregate function [{}], use HAVING instead",
676+
Expressions.name(e)));
677+
678+
}
670679
}
671680
});
672681
}

x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/analysis/analyzer/VerifierErrorMessagesTests.java

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -910,7 +910,24 @@ public void testIifWithDifferentResultAndDefaultValueDataTypes() {
910910

911911
public void testAggsInWhere() {
912912
assertEquals("1:33: Cannot use WHERE filtering on aggregate function [MAX(int)], use HAVING instead",
913-
error("SELECT MAX(int) FROM test WHERE MAX(int) > 10 GROUP BY bool"));
913+
error("SELECT MAX(int) FROM test WHERE MAX(int) > 10 GROUP BY bool"));
914+
}
915+
916+
public void testHavingInAggs() {
917+
assertEquals("1:29: [int] field must appear in the GROUP BY clause or in an aggregate function",
918+
error("SELECT int FROM test HAVING MAX(int) = 0"));
919+
920+
assertEquals("1:35: [int] field must appear in the GROUP BY clause or in an aggregate function",
921+
error("SELECT int FROM test HAVING int = count(1)"));
922+
}
923+
924+
public void testHavingAsWhere() {
925+
// TODO: this query works, though it normally shouldn't; a check about it could only be enforced if the Filter would be qualified
926+
// (WHERE vs HAVING). Otoh, this "extra flexibility" shouldn't be harmful atp.
927+
accept("SELECT int FROM test HAVING int = 1");
928+
accept("SELECT int FROM test HAVING SIN(int) + 5 > 5.5");
929+
// HAVING's expression being AND'ed to WHERE's
930+
accept("SELECT int FROM test WHERE int > 3 HAVING POWER(int, 2) < 100");
914931
}
915932

916933
public void testHistogramInFilter() {

0 commit comments

Comments
 (0)