Skip to content

Commit 0e044d7

Browse files
[ES|QL] Verify aggregation filter's type is boolean to avoid class_cast_exception (#116274)
* validate agg filter's type is boolean
1 parent 14a7b8f commit 0e044d7

File tree

3 files changed

+23
-0
lines changed

3 files changed

+23
-0
lines changed

docs/changelog/116274.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
pr: 116274
2+
summary: "[ES|QL] Verify aggregation filter's type is boolean to avoid `class_cast_exception`"
3+
area: ES|QL
4+
type: bug
5+
issues: []

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969
import static org.elasticsearch.xpack.esql.common.Failure.fail;
7070
import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.FIRST;
7171
import static org.elasticsearch.xpack.esql.core.type.DataType.BOOLEAN;
72+
import static org.elasticsearch.xpack.esql.core.type.DataType.NULL;
7273

7374
/**
7475
* This class is part of the planner. Responsible for failing impossible queries with a human-readable error message. In particular, this
@@ -315,6 +316,10 @@ private static void checkInvalidNamedExpressionUsage(
315316
Expression filter = fe.filter();
316317
failures.add(fail(filter, "WHERE clause allowed only for aggregate functions, none found in [{}]", fe.sourceText()));
317318
}
319+
Expression f = fe.filter(); // check the filter has to be a boolean term, similar as checkFilterConditionType
320+
if (f.dataType() != NULL && f.dataType() != BOOLEAN) {
321+
failures.add(fail(f, "Condition expression needs to be boolean, found [{}]", f.dataType()));
322+
}
318323
// but that the filter doesn't use grouping or aggregate functions
319324
fe.filter().forEachDown(c -> {
320325
if (c instanceof AggregateFunction af) {

x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/VerifierTests.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,19 @@ public void testAggFilterOnBucketingOrAggFunctions() {
394394
assertEquals("1:60: Unknown column [m]", error("from test | stats m = max(languages), min(languages) WHERE m + 2 > 1 by emp_no"));
395395
}
396396

397+
public void testAggWithNonBooleanFilter() {
398+
for (String filter : List.of("\"true\"", "1", "1 + 0", "concat(\"a\", \"b\")")) {
399+
String type = (filter.equals("1") || filter.equals("1 + 0")) ? "INTEGER" : "KEYWORD";
400+
assertEquals("1:19: Condition expression needs to be boolean, found [" + type + "]", error("from test | where " + filter));
401+
for (String by : List.of("", " by languages", " by bucket(salary, 10)")) {
402+
assertEquals(
403+
"1:34: Condition expression needs to be boolean, found [" + type + "]",
404+
error("from test | stats count(*) where " + filter + by)
405+
);
406+
}
407+
}
408+
}
409+
397410
public void testGroupingInsideAggsAsAgg() {
398411
assertEquals(
399412
"1:18: can only use grouping function [bucket(emp_no, 5.)] part of the BY clause",

0 commit comments

Comments
 (0)