Skip to content

Commit 8f45b6b

Browse files
authored
Disallow ES|QL CATEGORIZE in aggregation filters (elastic#118319) (elastic#118330)
1 parent e04fe26 commit 8f45b6b

File tree

2 files changed

+37
-3
lines changed

2 files changed

+37
-3
lines changed

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

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,18 @@ private static void checkCategorizeGrouping(Aggregate agg, Set<Failure> failures
382382
);
383383
}
384384
})));
385+
agg.aggregates().forEach(a -> a.forEachDown(FilteredExpression.class, fe -> fe.filter().forEachDown(Attribute.class, attribute -> {
386+
var categorize = categorizeByAttribute.get(attribute);
387+
if (categorize != null) {
388+
failures.add(
389+
fail(
390+
attribute,
391+
"cannot reference CATEGORIZE grouping function [{}] within an aggregation filter",
392+
attribute.sourceText()
393+
)
394+
);
395+
}
396+
})));
385397
}
386398

387399
private static void checkRateAggregates(Expression expr, int nestedLevel, Set<Failure> failures) {
@@ -421,7 +433,8 @@ private static void checkInvalidNamedExpressionUsage(
421433
Expression filter = fe.filter();
422434
failures.add(fail(filter, "WHERE clause allowed only for aggregate functions, none found in [{}]", fe.sourceText()));
423435
}
424-
Expression f = fe.filter(); // check the filter has to be a boolean term, similar as checkFilterConditionType
436+
Expression f = fe.filter();
437+
// check the filter has to be a boolean term, similar as checkFilterConditionType
425438
if (f.dataType() != NULL && f.dataType() != BOOLEAN) {
426439
failures.add(fail(f, "Condition expression needs to be boolean, found [{}]", f.dataType()));
427440
}
@@ -432,9 +445,10 @@ private static void checkInvalidNamedExpressionUsage(
432445
fail(af, "cannot use aggregate function [{}] in aggregate WHERE clause [{}]", af.sourceText(), fe.sourceText())
433446
);
434447
}
435-
// check the bucketing function against the group
448+
// check the grouping function against the group
436449
else if (c instanceof GroupingFunction gf) {
437-
if (Expressions.anyMatch(groups, ex -> ex instanceof Alias a && a.child().semanticEquals(gf)) == false) {
450+
if (c instanceof Categorize
451+
|| Expressions.anyMatch(groups, ex -> ex instanceof Alias a && a.child().semanticEquals(gf)) == false) {
438452
failures.add(fail(gf, "can only use grouping function [{}] as part of the BY clause", gf.sourceText()));
439453
}
440454
}

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

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1968,6 +1968,26 @@ public void testCategorizeWithinAggregations() {
19681968
);
19691969
}
19701970

1971+
public void testCategorizeWithFilteredAggregations() {
1972+
assumeTrue("requires Categorize capability", EsqlCapabilities.Cap.CATEGORIZE_V5.isEnabled());
1973+
1974+
query("FROM test | STATS COUNT(*) WHERE first_name == \"John\" BY CATEGORIZE(last_name)");
1975+
query("FROM test | STATS COUNT(*) WHERE last_name == \"Doe\" BY CATEGORIZE(last_name)");
1976+
1977+
assertEquals(
1978+
"1:34: can only use grouping function [CATEGORIZE(first_name)] as part of the BY clause",
1979+
error("FROM test | STATS COUNT(*) WHERE CATEGORIZE(first_name) == \"John\" BY CATEGORIZE(last_name)")
1980+
);
1981+
assertEquals(
1982+
"1:34: can only use grouping function [CATEGORIZE(last_name)] as part of the BY clause",
1983+
error("FROM test | STATS COUNT(*) WHERE CATEGORIZE(last_name) == \"Doe\" BY CATEGORIZE(last_name)")
1984+
);
1985+
assertEquals(
1986+
"1:34: cannot reference CATEGORIZE grouping function [category] within an aggregation filter",
1987+
error("FROM test | STATS COUNT(*) WHERE category == \"Doe\" BY category = CATEGORIZE(last_name)")
1988+
);
1989+
}
1990+
19711991
public void testSortByAggregate() {
19721992
assertEquals("1:18: Aggregate functions are not allowed in SORT [COUNT]", error("ROW a = 1 | SORT count(*)"));
19731993
assertEquals("1:28: Aggregate functions are not allowed in SORT [COUNT]", error("ROW a = 1 | SORT to_string(count(*))"));

0 commit comments

Comments
 (0)