1717import org .elasticsearch .xpack .esql .core .expression .Expression ;
1818import org .elasticsearch .xpack .esql .core .expression .Expressions ;
1919import org .elasticsearch .xpack .esql .core .expression .FieldAttribute ;
20+ import org .elasticsearch .xpack .esql .core .expression .NameId ;
2021import org .elasticsearch .xpack .esql .core .expression .NamedExpression ;
2122import org .elasticsearch .xpack .esql .core .expression .TypeResolutions ;
2223import org .elasticsearch .xpack .esql .core .expression .function .Function ;
3334import org .elasticsearch .xpack .esql .expression .function .fulltext .FullTextFunction ;
3435import org .elasticsearch .xpack .esql .expression .function .fulltext .Match ;
3536import org .elasticsearch .xpack .esql .expression .function .fulltext .QueryString ;
37+ import org .elasticsearch .xpack .esql .expression .function .grouping .Categorize ;
3638import org .elasticsearch .xpack .esql .expression .function .grouping .GroupingFunction ;
3739import org .elasticsearch .xpack .esql .expression .predicate .operator .arithmetic .Neg ;
3840import org .elasticsearch .xpack .esql .expression .predicate .operator .comparison .Equals ;
5658import java .util .ArrayList ;
5759import java .util .BitSet ;
5860import java .util .Collection ;
61+ import java .util .HashMap ;
5962import java .util .HashSet ;
6063import java .util .LinkedHashSet ;
6164import java .util .List ;
6265import java .util .Locale ;
66+ import java .util .Map ;
6367import java .util .Set ;
6468import java .util .function .BiConsumer ;
6569import java .util .function .Consumer ;
@@ -271,6 +275,7 @@ private static void checkAggregate(LogicalPlan p, Set<Failure> failures) {
271275 r -> failures .add (fail (r , "the rate aggregate[{}] can only be used within the metrics command" , r .sourceText ()))
272276 );
273277 }
278+ checkCategorizeGrouping (agg , failures );
274279 } else {
275280 p .forEachExpression (
276281 GroupingFunction .class ,
@@ -279,6 +284,74 @@ private static void checkAggregate(LogicalPlan p, Set<Failure> failures) {
279284 }
280285 }
281286
287+ /**
288+ * Check CATEGORIZE grouping function usages.
289+ * <p>
290+ * Some of those checks are temporary, until the required syntax or engine changes are implemented.
291+ * </p>
292+ */
293+ private static void checkCategorizeGrouping (Aggregate agg , Set <Failure > failures ) {
294+ // Forbid CATEGORIZE grouping function with other groupings
295+ if (agg .groupings ().size () > 1 ) {
296+ agg .groupings ().forEach (g -> {
297+ g .forEachDown (
298+ Categorize .class ,
299+ categorize -> failures .add (
300+ fail (categorize , "cannot use CATEGORIZE grouping function [{}] with multiple groupings" , categorize .sourceText ())
301+ )
302+ );
303+ });
304+ }
305+
306+ // Forbid CATEGORIZE grouping functions not being top level groupings
307+ agg .groupings ().forEach (g -> {
308+ // Check all CATEGORIZE but the top level one
309+ Alias .unwrap (g )
310+ .children ()
311+ .forEach (
312+ child -> child .forEachDown (
313+ Categorize .class ,
314+ c -> failures .add (
315+ fail (c , "CATEGORIZE grouping function [{}] can't be used within other expressions" , c .sourceText ())
316+ )
317+ )
318+ );
319+ });
320+
321+ // Forbid CATEGORIZE being used in the aggregations
322+ agg .aggregates ().forEach (a -> {
323+ a .forEachDown (
324+ Categorize .class ,
325+ categorize -> failures .add (
326+ fail (categorize , "cannot use CATEGORIZE grouping function [{}] within the aggregations" , categorize .sourceText ())
327+ )
328+ );
329+ });
330+
331+ // Forbid CATEGORIZE being referenced in the aggregation functions
332+ Map <NameId , Categorize > categorizeByAliasId = new HashMap <>();
333+ agg .groupings ().forEach (g -> {
334+ g .forEachDown (Alias .class , alias -> {
335+ if (alias .child () instanceof Categorize categorize ) {
336+ categorizeByAliasId .put (alias .id (), categorize );
337+ }
338+ });
339+ });
340+ agg .aggregates ()
341+ .forEach (a -> a .forEachDown (AggregateFunction .class , aggregate -> aggregate .forEachDown (Attribute .class , attribute -> {
342+ var categorize = categorizeByAliasId .get (attribute .id ());
343+ if (categorize != null ) {
344+ failures .add (
345+ fail (
346+ attribute ,
347+ "cannot reference CATEGORIZE grouping function [{}] within the aggregations" ,
348+ attribute .sourceText ()
349+ )
350+ );
351+ }
352+ })));
353+ }
354+
282355 private static void checkRateAggregates (Expression expr , int nestedLevel , Set <Failure > failures ) {
283356 if (expr instanceof AggregateFunction ) {
284357 nestedLevel ++;
0 commit comments