diff --git a/docs/changelog/132934.yaml b/docs/changelog/132934.yaml new file mode 100644 index 0000000000000..bd7b0bfd70f74 --- /dev/null +++ b/docs/changelog/132934.yaml @@ -0,0 +1,5 @@ +pr: 132934 +summary: Support filters on inlinestats +area: ES|QL +type: enhancement +issues: [] diff --git a/x-pack/plugin/esql/qa/server/multi-clusters/src/javaRestTest/java/org/elasticsearch/xpack/esql/ccq/MultiClusterSpecIT.java b/x-pack/plugin/esql/qa/server/multi-clusters/src/javaRestTest/java/org/elasticsearch/xpack/esql/ccq/MultiClusterSpecIT.java index b140f7ded44f0..9e1ed7417efe6 100644 --- a/x-pack/plugin/esql/qa/server/multi-clusters/src/javaRestTest/java/org/elasticsearch/xpack/esql/ccq/MultiClusterSpecIT.java +++ b/x-pack/plugin/esql/qa/server/multi-clusters/src/javaRestTest/java/org/elasticsearch/xpack/esql/ccq/MultiClusterSpecIT.java @@ -51,7 +51,7 @@ import static org.elasticsearch.xpack.esql.action.EsqlCapabilities.Cap.ENABLE_LOOKUP_JOIN_ON_REMOTE; import static org.elasticsearch.xpack.esql.action.EsqlCapabilities.Cap.FORK_V9; import static org.elasticsearch.xpack.esql.action.EsqlCapabilities.Cap.INLINESTATS; -import static org.elasticsearch.xpack.esql.action.EsqlCapabilities.Cap.INLINESTATS_V9; +import static org.elasticsearch.xpack.esql.action.EsqlCapabilities.Cap.INLINESTATS_V10; import static org.elasticsearch.xpack.esql.action.EsqlCapabilities.Cap.JOIN_LOOKUP_V12; import static org.elasticsearch.xpack.esql.action.EsqlCapabilities.Cap.JOIN_PLANNING_V1; import static org.elasticsearch.xpack.esql.action.EsqlCapabilities.Cap.METADATA_FIELDS_REMOTE_TEST; @@ -137,7 +137,7 @@ protected void shouldSkipTest(String testName) throws IOException { assumeTrue("Test " + testName + " is skipped on " + oldVersion, isEnabled(testName, instructions, oldVersion)); assumeFalse("INLINESTATS not yet supported in CCS", testCase.requiredCapabilities.contains(INLINESTATS.capabilityName())); assumeFalse("INLINESTATS not yet supported in CCS", testCase.requiredCapabilities.contains(JOIN_PLANNING_V1.capabilityName())); - assumeFalse("INLINESTATS not yet supported in CCS", testCase.requiredCapabilities.contains(INLINESTATS_V9.capabilityName())); + assumeFalse("INLINESTATS not yet supported in CCS", testCase.requiredCapabilities.contains(INLINESTATS_V10.capabilityName())); if (testCase.requiredCapabilities.contains(JOIN_LOOKUP_V12.capabilityName())) { assumeTrue( "LOOKUP JOIN not yet supported in CCS", diff --git a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/inlinestats.csv-spec b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/inlinestats.csv-spec index b90135f43a417..d0381725d5c34 100644 --- a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/inlinestats.csv-spec +++ b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/inlinestats.csv-spec @@ -1,9 +1,5 @@ -// -// TODO: re-enable the commented tests once the Join functionality stabilizes -// - allFieldsReturned -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 FROM hosts METADATA _index | INLINESTATS c = COUNT(*) BY host_group @@ -16,7 +12,7 @@ eth0 |epsilon gw instance|epsilon |[fe80::cae2:65ff:fece:feb9, ; maxOfInt -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 // tag::max-languages[] FROM employees | KEEP emp_no, languages @@ -38,7 +34,7 @@ emp_no:integer | languages:integer | max_lang:integer ; maxOfIntByKeyword -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 FROM employees | KEEP emp_no, languages, gender @@ -56,7 +52,7 @@ emp_no:integer | languages:integer | max_lang:integer | gender:keyword ; maxOfLongByKeyword -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 FROM employees | KEEP emp_no, avg_worked_seconds, gender @@ -71,7 +67,7 @@ emp_no:integer | avg_worked_seconds:long | max_avg_worked_seconds:long | gender: ; maxOfLong -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 FROM employees | KEEP emp_no, avg_worked_seconds, gender @@ -84,7 +80,7 @@ emp_no:integer | avg_worked_seconds:long | gender:keyword | max_avg_worked_secon ; maxOfLongByCalculatedKeyword -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 // tag::longest-tenured-by-first[] FROM employees @@ -107,7 +103,7 @@ emp_no:integer | avg_worked_seconds:long | last_name:keyword | max_avg_worked_se ; maxOfLongByCalculatedNamedKeyword -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 FROM employees | KEEP emp_no, avg_worked_seconds, last_name @@ -126,7 +122,7 @@ emp_no:integer | avg_worked_seconds:long | last_name:keyword | max_avg_worked_se ; maxOfLongByCalculatedDroppedKeyword -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 FROM employees | INLINESTATS max_avg_worked_seconds = MAX(avg_worked_seconds) BY l = SUBSTRING(last_name, 0, 1) @@ -145,7 +141,7 @@ emp_no:integer | avg_worked_seconds:long | last_name:keyword | max_avg_worked_se ; maxOfLongByEvaledKeyword -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 FROM employees | EVAL l = SUBSTRING(last_name, 0, 1) @@ -165,7 +161,7 @@ emp_no:integer | avg_worked_seconds:long | max_avg_worked_seconds:long | l:keywo ; maxOfLongByInt -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 FROM employees | KEEP emp_no, avg_worked_seconds, languages @@ -183,7 +179,7 @@ emp_no:integer | avg_worked_seconds:long | max_avg_worked_seconds:long | languag ; maxOfLongByIntDouble -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 FROM employees | KEEP emp_no, avg_worked_seconds, languages, height @@ -201,7 +197,7 @@ emp_no:integer | avg_worked_seconds:long | max_avg_worked_seconds:long | languag ; two -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 FROM employees | KEEP emp_no, languages, avg_worked_seconds, gender @@ -225,8 +221,7 @@ emp_no:integer |avg_worked_seconds:long|avg_avg_worked_seconds:double|languages: ; three -required_capability: inlinestats_v9 -// used to fail with AssertionError at org.elasticsearch.xpack.esql.plan.logical.Limit.writeTo(Limit.java:70) +required_capability: inlinestats_v10 FROM employees | KEEP emp_no, languages, avg_worked_seconds, gender @@ -253,7 +248,7 @@ emp_no:integer |avg_worked_seconds:long|avg_avg_worked_seconds:double|languages: // TODO: INLINESTATS unit test needed for this one pushDownSort_To_LeftSideOnly -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 from employees | sort emp_no @@ -271,7 +266,7 @@ from employees ; byMultivaluedSimple -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 // tag::mv-group[] FROM airports @@ -289,7 +284,7 @@ abbrev:keyword | type:keyword | scalerank:integer | min_scalerank:integer ; byMultivaluedMvExpand -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 // tag::mv-expand[] FROM airports @@ -309,7 +304,7 @@ GWL |9 |4 |military ; byMvExpand -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 // tag::extreme-airports[] FROM airports @@ -338,7 +333,7 @@ FROM airports ; mvMinMvExpand -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 FROM airports | EVAL original_type = type @@ -361,7 +356,7 @@ ZAR |Zaria |POINT (7.7 11.0667) |Nigeria |POINT ( ; afterStats -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 FROM airports | STATS count=COUNT(*) BY country @@ -384,7 +379,7 @@ count:long | country:keyword | avg:double ; afterWhere -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 FROM airports | WHERE country != "United States" @@ -402,7 +397,7 @@ abbrev:keyword | country:keyword | count:long ; afterLookup -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 required_capability: join_lookup_v12 FROM airports @@ -426,7 +421,7 @@ ZNZ |4 |German ; afterEnrich -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 required_capability: enrich_load FROM airports @@ -447,7 +442,7 @@ abbrev:keyword | city:keyword | "COUNT(*)":long | region:text ; beforeStats -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 FROM airports | EVAL lat = ST_Y(location) @@ -460,7 +455,7 @@ northern:long | southern:long ; beforeKeepSort -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 FROM employees | INLINESTATS max_salary = MAX(salary) by languages @@ -475,7 +470,7 @@ emp_no:integer | languages:integer | max_salary:integer ; beforeKeepWhere -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 FROM employees | INLINESTATS max_salary = MAX(salary) by languages @@ -488,7 +483,7 @@ emp_no:integer | languages:integer | max_salary:integer ; beforeEnrich -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 required_capability: enrich_load FROM airports @@ -507,7 +502,7 @@ ACA |Acapulco de Juárez|385 |major |Acapulco de ; beforeAndAfterEnrich -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 required_capability: enrich_load FROM airports @@ -530,7 +525,7 @@ ALL |Albenga |499 |mid |1 ; shadowing -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 ROW left = "left", client_ip = "172.21.0.5", env = "env", right = "right" | INLINESTATS env = VALUES(right) BY client_ip @@ -541,7 +536,7 @@ left | right | right | 172.21.0.5 ; shadowingMulti -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 ROW left = "left", airport = "Zurich Airport ZRH", city = "Zürich", middle = "middle", region = "North-East Switzerland", right = "right" | INLINESTATS airport=VALUES(left), region=VALUES(left), city_boundary=VALUES(left) BY city @@ -552,7 +547,7 @@ left | middle | right | left | left ; shadowingSelf -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 ROW city = "Raleigh" | INLINESTATS city = COUNT(city) @@ -563,7 +558,7 @@ city:long ; shadowingSelfBySelf -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 ROW city = "Raleigh" | INLINESTATS city = COUNT(city) BY city @@ -575,7 +570,7 @@ Raleigh ; shadowingInternal -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 ROW city = "Zürich" | INLINESTATS x = VALUES(city), x = VALUES(city) @@ -587,7 +582,7 @@ Zürich | Zürich ; multiInlinestatsWithRow -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 row x = 1 | inlinestats x = max(x) + min(x) @@ -601,7 +596,7 @@ row x = 1 ; ignoreUnusedEvaledValue_AndInlineStats -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 ROW x = 1 | INLINESTATS max(x) @@ -614,7 +609,7 @@ x:integer ; ignoreUnusedEvaledValue_AndInlineStats2 -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 ROW x = 1, z = 2 | INLINESTATS max(x) @@ -627,7 +622,7 @@ x:integer | z:integer ; ignoreUnusedEvaledValue_AndInlineStats3 -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 from employees | inlinestats max(salary) @@ -642,7 +637,7 @@ from employees ; ignoreUnusedEvaledValue_AndInlineStats4 -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 from employees | inlinestats max(salary), m = min(salary) by gender @@ -657,7 +652,7 @@ emp_no:integer ; ignoreUnusedEvaledValue_AndInlineStats5 -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 from employees | inlinestats max(salary), m = min(salary) by gender @@ -672,7 +667,7 @@ emp_no:integer ; shadowEntireInlinestats -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 FROM employees | INLINESTATS x = avg(salary), y = min(salary) BY emp_no @@ -687,7 +682,7 @@ x:integer |y:integer |emp_no:integer ; byConstant -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 FROM employees | KEEP emp_no, languages @@ -706,7 +701,7 @@ emp_no:integer | languages:integer | max_lang:integer | y:integer ; aggConstant -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 FROM employees | KEEP emp_no @@ -724,7 +719,7 @@ one:integer | emp_no:integer ; percentile -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 FROM employees | KEEP emp_no, salary @@ -743,7 +738,7 @@ emp_no:integer | salary:integer | ninety_fifth_salary:double ; byTwoCalculated -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 FROM airports | WHERE abbrev IS NOT NULL @@ -763,7 +758,7 @@ abbrev:keyword | scalerank:integer | location:geo_point byTwoCalculatedSecondOverwrites required_capability: stats_alias_collision_warnings -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 FROM airports | WHERE abbrev IS NOT NULL @@ -784,7 +779,7 @@ abbrev:keyword | scalerank:integer | location:geo_point byTwoCalculatedSecondOverwritesReferencingFirst required_capability: stats_alias_collision_warnings -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 FROM airports | WHERE abbrev IS NOT NULL @@ -807,7 +802,7 @@ abbrev:keyword | scalerank:integer | location:geo_point groupShadowsAgg required_capability: stats_alias_collision_warnings -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 FROM airports | WHERE abbrev IS NOT NULL @@ -827,7 +822,7 @@ abbrev:keyword | scalerank:integer | location:geo_point ; groupShadowsField -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 FROM employees | KEEP emp_no, salary, hire_date @@ -846,7 +841,7 @@ emp_no:integer | salary:integer | avg_salary:double | hire_date:datetime ; groupByExpression_And_ExistentField -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 FROM employees | KEEP emp_no, languages, gender | EVAL x = "ABC" @@ -864,7 +859,7 @@ emp_no:integer | languages:integer | x:keyword | max_lang:integer | y:keyword | ; groupByRenamedColumn -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 FROM employees | KEEP emp_no, languages, gender | INLINESTATS max_lang = MAX(languages) BY y = gender @@ -881,9 +876,8 @@ emp_no:integer | languages:integer | gender:keyword | max_lang:integer | y:keywo 10014 | 5 | null | 5 | null ; -// fails with AssertionError at org.elasticsearch.xpack.esql.plan.logical.Limit.writeTo(Limit.java:70) groupByMultipleRenamedColumns_AndOneExpression_Last -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 FROM employees | KEEP emp_no, languages, gender, first_name @@ -905,9 +899,8 @@ emp_no:integer | languages:integer | gender:keyword|first_name:keyword|max_lang: 10010 |4 |null |Duangkaew |4 |null |4 |D ; -// fails with AssertionError at org.elasticsearch.xpack.esql.plan.logical.Limit.writeTo(Limit.java:70) groupByMultipleRenamedColumns_AndTwoExpressions -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 FROM employees | KEEP emp_no, languages, gender, first_name @@ -929,9 +922,8 @@ emp_no:integer | languages:integer | gender:keyword|first_name:keyword|max_lang: 10010 |4 |null |Duangkaew |4 |D |null |D |4 ; -// fails with AssertionError at org.elasticsearch.xpack.esql.plan.logical.Limit.writeTo(Limit.java:70) groupByMultipleRenamedColumns_AndMultipleRenames -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 FROM employees | KEEP emp_no, languages, gender, first_name @@ -954,9 +946,8 @@ emp_no:integer | languages:integer | gender:keyword| f:keyword |max_lang: 10010 |4 |null |Duangkaew |4 |null |4 |D ; -// fails with AssertionError at org.elasticsearch.xpack.esql.plan.logical.Limit.writeTo(Limit.java:70) groupByMultipleRenamedColumns_AndSameNameExpressionGroupingOverride -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 FROM employees | KEEP emp_no, languages, gender, first_name @@ -980,7 +971,7 @@ emp_no:integer | languages:integer | gender:keyword|max_lang:integer| y:keyword ; twoAggregatesGroupedBy_AField_And_AnExpression -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 FROM employees | KEEP emp_no, languages, gender, last_name @@ -1002,7 +993,7 @@ emp_no:integer |languages:integer|last_name:keyword|max_lang:integer|min_lang:in ; groupByMultipleRenamedColumns_InversedOrder -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 FROM employees | KEEP emp_no, languages, still_hired, gender @@ -1020,7 +1011,7 @@ emp_no:integer |languages:integer|still_hired:boolean| gender:keyword|max_lang:i ; groupByMultipleRenamedColumns_InversedOrder_ComplexEval -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 FROM employees | KEEP emp_no, languages, still_hired, gender @@ -1039,7 +1030,7 @@ emp_no:integer |languages:integer|still_hired:boolean| gender:keyword|multilingu ; groupByMultipleRenamedColumns_AndComplexEval -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 FROM employees | KEEP emp_no, languages, still_hired, gender @@ -1057,9 +1048,8 @@ emp_no:integer |languages:integer|still_hired:boolean| gender:keyword|multilingu 10005 |1 |true |M |monolingual |1 |M |true |monolingual ; -// fails with AssertionError at org.elasticsearch.xpack.esql.plan.logical.Limit.writeTo(Limit.java:70) groupByMultipleRenamedColumns_AndConstantValue -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 FROM employees | KEEP emp_no, languages, gender, first_name @@ -1083,7 +1073,7 @@ emp_no:integer |languages:integer|gender:keyword |first_name:keyword | x:keyw ; groupByRenamedExpression -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 FROM employees | KEEP emp_no, languages, gender, last_name @@ -1105,7 +1095,7 @@ emp_no:integer |languages:integer|last_name:keyword|max_lang:integer|min_lang:in ; doubleFilterOnLeftAndRight_InlineStats_Sides -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 FROM employees | INLINESTATS max_salary = MAX(salary), min_salary = MIN(salary) by languages @@ -1126,7 +1116,7 @@ emp_no:integer |languages:integer|salary:integer |max_salary:integer|min_salary: ; filterOnInlineStatsAggs -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 FROM employees | INLINESTATS max_salary = MAX(salary), min_salary = MIN(salary) by languages @@ -1145,7 +1135,7 @@ emp_no:integer |languages:integer|salary:integer |max_salary:integer|min_salary: ; filterOnInlineStatsAggsValues_And_Groupings -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 FROM employees | INLINESTATS max_salary = MAX(salary), min_salary = MIN(salary) by languages @@ -1164,7 +1154,7 @@ emp_no:integer |languages:integer|salary:integer |max_salary:integer|min_salary: ; inlineStatsOverrideEVALed_FieldWithSameName -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 FROM hosts METADATA _index | EVAL x = ip1 @@ -1178,7 +1168,7 @@ beta k8s server |beta |127.0.0.1 |hosts |127.0.0.2|2 ; doubleShadowing -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 FROM employees | INLINESTATS salary = min(salary) BY gender @@ -1197,7 +1187,7 @@ salary:integer |gender:keyword ; doubleShadowing_WithIntertwinedFilters -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 FROM employees | WHERE salary > 30000 @@ -1222,7 +1212,7 @@ salary:integer |gender:keyword ; shadowingAggregateByNextGrouping -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 FROM employees | KEEP gender, languages, emp_no, salary @@ -1239,7 +1229,7 @@ emp_no:integer |salary:integer |languages:integer|avg(salary):double|gender:long ; doubleShadowingWithEval -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 from employees | eval salary = salary/100 @@ -1259,7 +1249,7 @@ salary:integer|gender:keyword ; doubleShadowingWithDoubleStats -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 from employees | stats salary=min(salary) by gender @@ -1276,7 +1266,7 @@ M |25324 ; renamingGroupingWithItself -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 FROM employees | EVAL x = gender @@ -1295,7 +1285,7 @@ salary:integer |x:keyword|gender:keyword |min_sl:integer |emp_no:integer ; overridingGroupings -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 FROM employees | INLINESTATS min_sl = MIN(salary) BY x = gender, x = languages @@ -1314,7 +1304,7 @@ salary:integer |x:integer |gender:keyword |min_sl:integer |emp_no:integer ; overridingExpressionGroupings -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 FROM employees | INLINESTATS min_sl = MIN(salary) BY x = TO_LOWER(gender), x = CONCAT(gender, gender) @@ -1333,7 +1323,7 @@ salary:integer |x:keyword |gender:keyword |min_sl:integer |emp_no:integer ; reusingEvalExpressions_UsedInGroupings -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 FROM employees | KEEP salary, gender, emp_no @@ -1352,7 +1342,7 @@ salary:integer |gender:keyword |emp_no:integer |min_sl:integer | x:keyword ; statsBeforeInlinestatsWithTopAndBucket1 -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 FROM books | STATS avg_rating = AVG(ratings) BY decade = BUCKET(year, 10) @@ -1372,7 +1362,7 @@ avg_rating:double | decade:double | decades:double ; statsBeforeInlinestatsWithTopAndBucket2 -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 FROM sample_data | STATS total_duration = SUM(event_duration) BY day = BUCKET(@timestamp, 1 HOUR) @@ -1388,7 +1378,7 @@ total_duration:long | day:date | days:date evalBeforeInlinestatsAndKeepAfter1 -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 FROM employees | WHERE still_hired == false @@ -1408,7 +1398,7 @@ emp_no:integer |still_hired:boolean|totalK:long|count:long ; evalBeforeInlinestatsAndKeepAfter2 -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 FROM employees | EVAL salaryK = salary/1000 @@ -1428,7 +1418,7 @@ emp_no:integer |still_hired:boolean|total:long|count:long ; evalBeforeInlinestatsAndKeepAfter3 -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 FROM employees | EVAL salaryK = salary/1000 @@ -1447,7 +1437,7 @@ emp_no:integer |still_hired:boolean|total:long ; evalBeforeInlinestatsAndKeepAfter4 -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 FROM employees | EVAL salaryK = salary/1000 @@ -1466,7 +1456,7 @@ emp_no:integer |still_hired:boolean|count:long ; evalBeforeInlinestatsAndKeepAfter5 -required_capability: inlinestats_v9 +required_capability: inlinestats_v10 ROW salary = 12300, emp_no = 5, gender = "F" | EVAL salaryK = salary/1000 @@ -1477,3 +1467,947 @@ ROW salary = 12300, emp_no = 5, gender = "F" emp_no:integer 5 ; +/////////////////////////// +// inlinestats with filters +/////////////////////////// + +doubleFilterOnInlineStats +required_capability: inlinestats_v10 + +from employees +| keep salary, gender +| inlinestats max1 = max(salary) where salary < 60000, + max2 = max(salary) where salary < 70000 AND salary >= 60000, + max3 = max(salary) where salary >= 70000 + by gender +| sort salary desc +| limit 10 +; + +salary:integer | max1:integer | max2:integer | max3:integer | gender:keyword +74999 |58121 |68547 |74999 |M +74970 |58121 |68547 |74999 |M +74572 |56415 |69904 |74572 |F +73851 |56415 |69904 |74572 |F +73717 |58715 |61358 |73717 |null +73578 |56415 |69904 |74572 |F +71165 |58121 |68547 |74999 |M +70011 |58121 |68547 |74999 |M +69904 |56415 |69904 |74572 |F +68547 |58121 |68547 |74999 |M +; + +inlinestatsWithFiltering +required_capability: inlinestats_v10 +from employees +| inlinestats max = max(salary), max_f = max(salary) where salary < 50000, max_a = max(salary) where salary > 100, + min = min(salary), min_f = min(salary) where salary > 50000, min_a = min(salary) where salary > 100 +| keep max*, min*, salary +| sort salary asc +| limit 3 +; + +max:integer |max_f:integer |max_a:integer | min:integer | min_f:integer | min_a:integer | salary:integer +74999 |49818 |74999 |25324 |50064 |25324 |25324 +74999 |49818 |74999 |25324 |50064 |25324 |25945 +74999 |49818 |74999 |25324 |50064 |25324 |25976 +; + +inlinestatsWithEverythingFiltered +required_capability: inlinestats_v10 +from employees +| inlinestats max = max(salary), max_a = max(salary) where salary < 100, + min = min(salary), min_a = min(salary) where salary > 99999 +| keep max*, min*, emp_no*, salary +| sort emp_no desc +| limit 5 +; + +max:integer |max_a:integer|min:integer | min_a:integer | emp_no:integer|salary:integer +74999 |null |25324 |null |10100 |68431 +74999 |null |25324 |null |10099 |73578 +74999 |null |25324 |null |10098 |44817 +74999 |null |25324 |null |10097 |71165 +74999 |null |25324 |null |10096 |43889 +; + +inlinestatsWithNullFilter +required_capability: inlinestats_v10 +from employees +| inlinestats max = max(salary), max_a = max(salary) where null, + min = min(salary), min_a = min(salary) where to_string(null) == "abc" +| keep max*, min*, emp_no +| sort emp_no +| limit 3 +; + +max:integer |max_a:integer|min:integer | min_a:integer | emp_no:integer +74999 |null |25324 |null |10001 +74999 |null |25324 |null |10002 +74999 |null |25324 |null |10003 +; + +inlinestatsWithAllFiltersFalse +required_capability: inlinestats_v10 +from employees +| inlinestats max = max(height.float) where false, + min = min(height.float) where to_string(null) == "abc", + count = count(height.float) where false, + count_distinct = count_distinct(salary) where to_string(null) == "def" +| sort emp_no desc +| keep emp_no, salary, max, min, count* +| limit 3 +; + +emp_no:integer|salary:integer| max:double |min:double |count:long |count_distinct:long +10100 |68431 |null |null |0 |0 +10099 |73578 |null |null |0 |0 +10098 |44817 |null |null |0 |0 +; + +inlinestatsWithAllFiltersFalse_GroupByOneField +required_capability: inlinestats_v10 +from employees +| inlinestats max = max(height.float) where false, + min = min(height.float) where to_string(null) == "abc", + count = count(height.float) where false, + count_distinct = count_distinct(salary) where to_string(null) == "def" by gender +| sort emp_no desc +| keep emp_no, salary, max, min, count*, gender +| limit 5 +; + + emp_no:i | salary:i | max:d | min:d | count:l |count_distinct:l| gender:s +10100 |68431 |null |null |0 |0 |F +10099 |73578 |null |null |0 |0 |F +10098 |44817 |null |null |0 |0 |F +10097 |71165 |null |null |0 |0 |M +10096 |43889 |null |null |0 |0 |M +; + +inlinestatsWithAllFiltersFalse_GroupByTwoFields +required_capability: inlinestats_v10 +from employees +| inlinestats max = max(height.float) where false, + min = min(height.float) where to_string(null) == "abc", + count = count(height.float) where false, + count_distinct = count_distinct(salary) where to_string(null) == "def" by gender, languages +| sort emp_no desc +| keep emp_no, salary, max, min, count*, gender, languages +| limit 5 +; + + emp_no:i | salary:i | max:d | min:d | count:l |count_distinct:l| gender:s |languages:i +10100 |68431 |null |null |0 |0 |F |4 +10099 |73578 |null |null |0 |0 |F |2 +10098 |44817 |null |null |0 |0 |F |4 +10097 |71165 |null |null |0 |0 |M |3 +10096 |43889 |null |null |0 |0 |M |4 +; + +prunedInlinestatsFollowedByInlinestats_GroupByOneFieldEach_DifferentFields +required_capability: inlinestats_v10 +from employees +| eval my_length = length(concat(first_name, null)) +| inlinestats count = count(my_length) where false, + values = mv_slice(values(first_name), 0, 1) where my_length > 0 by languages +| keep emp_no, first_name, *length, count, values, languages, gender +| inlinestats count_distinct = count_distinct(count) by gender +| sort emp_no +| limit 3 +; + + emp_no:i | first_name:s | my_length:i | count:l | values:s | languages:i |count_distinct:l| gender:s +10001 |Georgi |null |0 |null |2 |1 |M +10002 |Bezalel |null |0 |null |5 |1 |F +10003 |Parto |null |0 |null |4 |1 |M +; + +prunedInlinestatsFollowedByInlinestats_GroupByOneFieldEach_SameFields +required_capability: inlinestats_v10 +from employees +| eval my_length = length(concat(first_name, null)) +| inlinestats count = count(my_length) where false, + values = mv_slice(values(first_name), 0, 1) where my_length > 0 by languages +| keep emp_no, first_name, *length, count, values, languages, gender +| inlinestats count_distinct = count_distinct(count) by languages +| sort emp_no +| limit 3 +; + + emp_no:i | first_name:s | my_length:i | count:l | values:s | gender:s |count_distinct:l| languages:i +10001 |Georgi |null |0 |null |M |1 |2 +10002 |Bezalel |null |0 |null |F |1 |5 +10003 |Parto |null |0 |null |M |1 |4 +; + +prunedInlinestatsFollowedByInlinestats_GroupByOneFieldOnSecondInlinestats-Ignore +// values doesn't end up as null +required_capability: inlinestats_v10 +from employees +| eval my_length = length(concat(first_name, null)) +| inlinestats count = count(my_length) where false, + values = mv_slice(values(first_name), 0, 1) where my_length > 0 +| keep emp_no, first_name, *length, count, values, languages, gender +| inlinestats count_distinct = count_distinct(count) by languages +| sort emp_no +| limit 3 +; + + emp_no:i | first_name:s | my_length:i | count:l | values:s | gender:s |count_distinct:l| languages:i +10001 |Georgi |null |0 |null |M |1 |2 +10002 |Bezalel |null |0 |null |F |1 |5 +10003 |Parto |null |0 |null |M |1 |4 +; + +partial_PrunedInlinestatsFollowedByInlinestats_GroupByOneFieldOnFirstInlinestats +required_capability: inlinestats_v10 +from employees +| eval my_length = length(concat(first_name, null)) +| inlinestats count = count(is_rehired) where true, + values = mv_slice(values(first_name), 0, 1) where my_length > 0 by gender +| keep emp_no, first_name, *length, count, values, languages, gender +| inlinestats count_distinct = count_distinct(count) +| sort emp_no +| limit 10 +; + + emp_no:i | first_name:s | my_length:i | count:l | values:s | languages:i | gender:s |count_distinct:l +10001 |Georgi |null |111 |null |2 |M |3 +10002 |Bezalel |null |65 |null |5 |F |3 +10003 |Parto |null |111 |null |4 |M |3 +10004 |Chirstian |null |111 |null |5 |M |3 +10005 |Kyoichi |null |111 |null |1 |M |3 +10006 |Anneke |null |65 |null |3 |F |3 +10007 |Tzvetan |null |65 |null |4 |F |3 +10008 |Saniya |null |111 |null |2 |M |3 +10009 |Sumant |null |65 |null |1 |F |3 +10010 |Duangkaew |null |28 |null |4 |null |3 +; + + +partial_PrunedInlinestatsFollowedByInlinestats_GroupByOneFieldOnFirstInlinestats2 +required_capability: inlinestats_v10 +from employees +| eval my_length = length(concat(first_name, null)) +| inlinestats count = count(is_rehired) where true, + values = mv_slice(values(first_name), 0, 1) where my_length > 0, + count_d = count_distinct(is_rehired) by gender +| keep emp_no, first_name, *length, count*, values, languages, gender +| inlinestats count_distinct = count_distinct(count) +| sort emp_no +| limit 10 +; + + emp_no:i | first_name:s | my_length:i | count:l | count_d:l | values:s | languages:i | gender:s |count_distinct:l +10001 |Georgi |null |111 |2 |null |2 |M |3 +10002 |Bezalel |null |65 |2 |null |5 |F |3 +10003 |Parto |null |111 |2 |null |4 |M |3 +10004 |Chirstian |null |111 |2 |null |5 |M |3 +10005 |Kyoichi |null |111 |2 |null |1 |M |3 +10006 |Anneke |null |65 |2 |null |3 |F |3 +10007 |Tzvetan |null |65 |2 |null |4 |F |3 +10008 |Saniya |null |111 |2 |null |2 |M |3 +10009 |Sumant |null |65 |2 |null |1 |F |3 +10010 |Duangkaew |null |28 |2 |null |4 |null |3 +; + + +inlinestatsWithExpressionsAllFiltersFalse +required_capability: inlinestats_v10 +from employees +| keep height.f*, emp_no +| sort emp_no desc +| inlinestats max = max(height.float + 1) where null, + count = count(height.float) + 2 where false, + mix = min(height.float + 1) + count_distinct(emp_no) + 2 where length(null) == 3 +| limit 3 +| drop height.float +; + + emp_no:i | max:d | count:l | mix:d +10100 |null |2 |null +10099 |null |2 |null +10098 |null |2 |null +; + +inlinestatsWithFalseFilterAndGroup +required_capability: inlinestats_v10 +from employees +| inlinestats max = max(height.float + 1) where null, + count = count(height.float) + 2 where false + by job_positions +| sort emp_no desc +| limit 4 +| keep emp_no, job_positions, height.float, max, count +; + + emp_no:i | job_positions:s | height.float:d | max:d | count:l +10100 |Purchase Manager |1.7699999809265137|null |2 +10099 |null |1.809999942779541 |null |2 +10098 |[Architect, Internship, Senior Team Lead]|2.0 |null |[2, 2, 2] +10097 |[Reporting Analyst, Tech Lead] |1.5299999713897705|null |[2, 2] +; + +inlinestatsWithFalseFiltersAndGroups +required_capability: inlinestats_v10 +from employees +| eval my_length = length(concat(first_name, null)) +| inlinestats count_distinct = count_distinct(height.float + 1) where null, + count = count(height.float) + 2 where false, + values = values(first_name) where my_length > 3 + by job_positions, is_rehired +| sort emp_no desc +| limit 10 +| keep emp_no, my_length, count*, values, job_positions, is_rehired +; + + emp_no:integer|my_length:integer|count_distinct:long| count:long |values:keyword | job_positions:keyword | is_rehired:boolean +10100 |null |[0, 0] |[2, 2] |null |Purchase Manager |[false, false, true, true] +10099 |null |0 |2 |null |null |[true, true] +10098 |null |[0, 0, 0] |[2, 2, 2] |null |[Architect, Internship, Senior Team Lead] |false +10097 |null |[0, 0, 0, 0] |[2, 2, 2, 2] |null |[Reporting Analyst, Tech Lead] |[false, true] +10096 |null |[0, 0] |[2, 2] |null |[Architect, Reporting Analyst] |[false, false, false] +10095 |null |[0, 0] |[2, 2] |null |null |[false, false, true, true] +10094 |null |[0, 0, 0, 0, 0, 0] |[2, 2, 2, 2, 2, 2]|null |[Accountant, Principal Support Engineer, Senior Python Developer] |[false, true, true] +10093 |null |[0, 0, 0, 0] |[2, 2, 2, 2] |null |[Principal Support Engineer, Purchase Manager, Reporting Analyst, Tech Lead]|null +10092 |null |[0, 0, 0, 0] |[2, 2, 2, 2] |null |[Accountant, Junior Developer] |[false, false, true, true] +10091 |null |[0, 0, 0, 0] |[2, 2, 2, 2] |null |[Python Developer, Reporting Analyst] |[false, false, true, true] +; + +inlinestatsWithFalseFiltersAndGroups_DropEvaledValue +required_capability: inlinestats_v10 +from employees +| eval my_length = length(concat(first_name, null)) +| inlinestats count_distinct = count_distinct(height.float + 1) where null, + count = count(height.float) + 2 where false, + values = values(first_name) where my_length > 3 + by job_positions, is_rehired +| sort emp_no desc +| limit 10 +| keep emp_no, count*, values, job_positions, is_rehired +; + + + emp_no:integer|count_distinct:long| count:long |values:keyword | job_positions:keyword | is_rehired:boolean +10100 |[0, 0] |[2, 2] |null |Purchase Manager |[false, false, true, true] +10099 |0 |2 |null |null |[true, true] +10098 |[0, 0, 0] |[2, 2, 2] |null |[Architect, Internship, Senior Team Lead] |false +10097 |[0, 0, 0, 0] |[2, 2, 2, 2] |null |[Reporting Analyst, Tech Lead] |[false, true] +10096 |[0, 0] |[2, 2] |null |[Architect, Reporting Analyst] |[false, false, false] +10095 |[0, 0] |[2, 2] |null |null |[false, false, true, true] +10094 |[0, 0, 0, 0, 0, 0] |[2, 2, 2, 2, 2, 2]|null |[Accountant, Principal Support Engineer, Senior Python Developer] |[false, true, true] +10093 |[0, 0, 0, 0] |[2, 2, 2, 2] |null |[Principal Support Engineer, Purchase Manager, Reporting Analyst, Tech Lead]|null +10092 |[0, 0, 0, 0] |[2, 2, 2, 2] |null |[Accountant, Junior Developer] |[false, false, true, true] +10091 |[0, 0, 0, 0] |[2, 2, 2, 2] |null |[Python Developer, Reporting Analyst] |[false, false, true, true] +; + +inlinestatsWithMixedFiltersAndGroup +required_capability: inlinestats_v10 +from employees +| eval my_length = length(concat(first_name, null)) +| inlinestats count = count(my_length) where false, + values = mv_slice(mv_sort(values(first_name)), 0, 1) + by job_positions +| sort emp_no +| limit 4 +| keep *length, count, values, job_positions, emp_no +; + +my_length:integer| count:long | values:keyword | job_positions:keyword |emp_no:integer +null |[0, 0] |[Arumugam, Bojan, Arumugam, Basil] |[Accountant, Senior Python Developer] |10001 +null |0 |[Alejandro, Anneke] |Senior Team Lead |10002 +null |0 |[Gino, Heping] |null |10003 +null |[0, 0, 0, 0] |[Berni, Chirstian, Amabile, Berni, Bojan, Chirstian, Anneke, Chirstian]|[Head Human Resources, Reporting Analyst, Support Engineer, Tech Lead]|10004 +; + +prunedInlinestatsFollowedByinlinestats-Ignore +// values doesn't end up as null +required_capability: inlinestats_v10 +from employees +| eval my_length = length(concat(first_name, null)) +| inlinestats count = count(my_length) where false, + values = mv_slice(values(first_name), 0, 1) where my_length > 0 +| keep emp_no, first_name, *length, count, values +| inlinestats count_distinct = count_distinct(count) +| sort emp_no +| limit 3 +; + + emp_no:i | first_name:s | my_length:i | count:l | values:s |count_distinct:l +10001 |Georgi |null |0 |null |1 +10002 |Bezalel |null |0 |null |1 +10003 |Parto |null |0 |null |1 +; + +inlinestatsWithFalseFiltersFromRow +// is this result correct? The stats variant of this query has this result: +// c:integer |b:integer +// null |2 +// null |3 +// null |4 +required_capability: inlinestats_v10 +row x = null, a = 1, b = [2,3,4] +| inlinestats c=max(a) where x + by b +; + + x:null | a:integer | c:integer | b:integer +null |1 |null |[2, 3, 4] +; + +inlinestatsWithBasicExpressionFiltered +required_capability: inlinestats_v10 +from employees +| inlinestats max = max(salary), max_f = max(salary) where salary < 50000, + min = min(salary), min_f = min(salary) where salary > 50000, + exp_p = max(salary) + 10000 where salary < 50000, + exp_m = min(salary) % 10000 where salary > 50000 +| keep max*, min*, exp*, emp_no | sort emp_no | limit 3 +; + + max:i | max_f:i | min:i | min_f:i | exp_p:i | exp_m:i | emp_no:i +74999 |49818 |25324 |50064 |59818 |64 |10001 +74999 |49818 |25324 |50064 |59818 |64 |10002 +74999 |49818 |25324 |50064 |59818 |64 |10003 +; + +inlinestatsWithExpressionOverFilters +required_capability: inlinestats_v10 +from employees +| inlinestats max = max(salary), max_f = max(salary) where salary < 50000, + min = min(salary), min_f = min(salary) where salary > 50000, + exp_gt = max(salary) - min(salary) where salary > 50000, + exp_lt = max(salary) - min(salary) where salary < 50000 +| keep max*, min*, exp*, emp_no +| sort emp_no +| limit 3 +; + + max:i | max_f:i | min:i | min_f:i | exp_gt:i | exp_lt:i | emp_no:i +74999 |49818 |25324 |50064 |24935 |24494 |10001 +74999 |49818 |25324 |50064 |24935 |24494 |10002 +74999 |49818 |25324 |50064 |24935 |24494 |10003 +; + + +inlinestatsWithExpressionOfExpressionsOverFilters +required_capability: inlinestats_v10 +from employees +| inlinestats max = max(salary + 1), max_f = max(salary + 2) where salary < 50000, + min = min(salary - 1), min_f = min(salary - 2) where salary > 50000, + exp_gt = max(salary + 3) - min(salary - 3) where salary > 50000, + exp_lt = max(salary + 4) - min(salary - 4) where salary < 50000 +| keep max*, min*, exp*, emp_no +| sort emp_no +| limit 3 +; + + max:i | max_f:i | min:i | min_f:i | exp_gt:i | exp_lt:i | emp_no:i +75000 |49820 |25323 |50062 |24941 |24502 |10001 +75000 |49820 |25323 |50062 |24941 |24502 |10002 +75000 |49820 |25323 |50062 |24941 |24502 |10003 +; + +inlinestatsWithSubstitutedExpressionOverFilters +required_capability: inlinestats_v10 +from employees +| inlinestats sum = sum(salary), s_l = sum(salary) where salary < 50000, s_u = sum(salary) where salary > 50000, + count = count(salary), c_l = count(salary) where salary < 50000, c_u = count(salary) where salary > 50000, + avg = round(avg(salary), 2), a_l = round(avg(salary), 2) where salary < 50000, a_u = round(avg(salary),2) where salary > 50000 +| keep sum, s_*, count, c_*, avg, a_*, emp_no +| sort emp_no +| limit 3 +; + + sum:l | s_l:l | s_u:l | count:l | c_l:l | c_u:l | avg:d | a_l:d | a_u:d | emp_no:i +4824855 |2220951 |2603904 |100 |58 |42 |48248.55 |38292.26 |61997.71 |10001 +4824855 |2220951 |2603904 |100 |58 |42 |48248.55 |38292.26 |61997.71 |10002 +4824855 |2220951 |2603904 |100 |58 |42 |48248.55 |38292.26 |61997.71 |10003 +; + + +inlinestatsWithFilterAndGroupBy +required_capability: inlinestats_v10 +from employees +| keep height, gender, is_rehired, emp_no +| inlinestats m = max(height), m_f = max(height + 1) where gender == "M" OR is_rehired is null BY gender, is_rehired +| sort emp_no +| drop height +| limit 10 +; + + emp_no:i | m:d | m_f:d | gender:s | is_rehired:boolean +10001 |[2.1, 2.1] |[3.1, 3.1] |M |[false, true] +10002 |2.1 |null |F |[false, false] +10003 |2.01 |3.01 |M |null +10004 |2.1 |3.1 |M |true +10005 |[2.1, 2.1] |[3.1, 3.1] |M |[false, false, false, true] +10006 |1.85 |2.85 |F |null +10007 |[2.1, 2.1] |null |F |[false, false, true, true] +10008 |[2.1, 2.1] |[3.1, 3.1] |M |[false, true] +10009 |1.85 |2.85 |F |null +10010 |[2.06, 1.97] |null |null |[false, false, true, true] +; + + +inlinestatsWithFilterOnGroupBy +required_capability: inlinestats_v10 +from employees +| inlinestats m_f = max(height) where gender == "M" BY gender +| sort emp_no +| keep gender, m_f +| limit 10 +; + + gender:s | m_f:d +M |2.1 +F |null +M |2.1 +M |2.1 +M |2.1 +F |null +F |null +M |2.1 +F |null +null |null +; + +inlinestatsWithGroupByLiteral +required_capability: inlinestats_v10 +from employees +| inlinestats m = max(languages) by salary = 2 +| sort salary +| keep m, salary +| limit 3 +; + + m:i | salary:i +5 |2 +5 |2 +5 |2 +; + + +inlinestatsWithFilterOnSameColumn +required_capability: inlinestats_v10 +from employees +| inlinestats m = max(languages), m_f = max(languages) where salary > 50000 by salary = 2 +| sort salary +| keep m, m_f, salary +| limit 3 +; + + m:i | m_f:i | salary:i +5 |null |2 +5 |null |2 +5 |null |2 +; + +inlinestatsWithFilteringAndGrouping +required_capability: inlinestats_v10 +from employees +| inlinestats c = count(), c_f = count(languages) where l > 1, + m_f = max(height) where salary > 50000 + by l = languages +| sort salary +| keep c, *_f, l, salary +| limit 10 +; + + c:l | c_f:l | m_f:d | l:i | salary:i +21 |21 |2.1 |5 |25324 +21 |21 |2.1 |5 |25945 +15 |0 |2.06 |1 |25976 +17 |17 |2.1 |3 |26436 +18 |18 |1.83 |4 |27215 +15 |0 |2.06 |1 |28035 +10 |0 |2.08 |null |28336 +17 |17 |2.1 |3 |28941 +19 |19 |2.03 |2 |29175 +17 |17 |2.1 |3 |30404 +; + + +multiinlinestatsWithFiltering +required_capability: inlinestats_v10 +from employees +| inlinestats c = count(), c_f = count(languages) where l > 1, + m_f = max(height) where salary > 50000 + by l = languages +| inlinestats c2 = count(), c2_f = count() where m_f > 2.06 , m2 = max(l), m2_f = max(l) where l > 1 by c +| sort emp_no +| where emp_no >= 10029 and emp_no <= 10039 +| keep c, *_f, l, c2, m2 +; + + c:l | c_f:l | m_f:d | c2_f:l | m2_f:i | l:i | c2:l | m2:i +10 |0 |2.08 |10 |null |null |10 |null +17 |17 |2.1 |17 |3 |3 |17 |3 +18 |18 |1.83 |0 |4 |4 |18 |4 +17 |17 |2.1 |17 |3 |3 |17 |3 +15 |0 |2.06 |0 |null |1 |15 |1 +15 |0 |2.06 |0 |null |1 |15 |1 +21 |21 |2.1 |21 |5 |5 |21 |5 +18 |18 |1.83 |0 |4 |4 |18 |4 +19 |19 |2.03 |0 |2 |2 |19 |2 +18 |18 |1.83 |0 |4 |4 |18 |4 +19 |19 |2.03 |0 |2 |2 |19 |2 +; + + +simpleCountOnFieldWithFilteringAndNoGrouping +required_capability: inlinestats_v10 +from employees +| inlinestats c1 = count(emp_no) where emp_no < 10042 +| keep emp_no, c1 +| sort emp_no +| limit 3 +; + +emp_no:integer | c1:long +10001 |41 +10002 |41 +10003 |41 +; + +simpleCountOnFieldWithFilteringOnDifferentFieldAndNoGrouping +required_capability: inlinestats_v10 +from employees +| inlinestats c1 = count(hire_date) where emp_no < 10042 +| keep emp_no, c1 +| sort emp_no +| limit 3 +; + +emp_no:integer | c1:long +10001 |41 +10002 |41 +10003 |41 +; + +simpleCountOnStarWithFilteringAndNoGrouping +required_capability: inlinestats_v10 +from employees +| inlinestats c1 = count(*) where emp_no < 10042 +| keep emp_no, c1 +| sort emp_no +| limit 3 +; + +emp_no:integer | c1:long +10001 |41 +10002 |41 +10003 |41 +; + +simpleCountWithFilteringAndNoGroupingOnFieldWithNulls +required_capability: inlinestats_v10 +from employees +| inlinestats c1 = count(birth_date) where emp_no <= 10050 +| keep emp_no, c1 +| sort emp_no +| limit 3 +; + +emp_no:integer | c1:long +10001 |40 +10002 |40 +10003 |40 +; + + +simpleCountWithFilteringAndNoGroupingOnFieldWithMultivalues +required_capability: inlinestats_v10 +from employees +| inlinestats c1 = count(job_positions) where emp_no <= 10003 +| keep emp_no, c1 +| sort emp_no +| limit 3 +; + + emp_no:integer| c1:long +10001 |3 +10002 |3 +10003 |3 +; + +commonFilterExtractionWithAliasing +required_capability: inlinestats_v10 +from employees +| eval eno = emp_no +| drop emp_no +| inlinestats min_sal = min(salary) where eno <= 10010, + min_hei = min(height) where eno <= 10010 +| keep eno, min_* +| sort eno +| limit 3 +; + + eno:integer |min_sal:integer|min_hei:double +10001 |36174 |1.56 +10002 |36174 |1.56 +10003 |36174 |1.56 +; + +commonFilterExtractionWithAliasAndOriginal +required_capability: inlinestats_v10 +from employees +| eval eno = emp_no +| inlinestats min_sal = min(salary) where eno <= 10010, + min_hei = min(height) where emp_no <= 10010 +| keep emp_no, min_* +| sort emp_no +| limit 3 +; + + emp_no:integer|min_sal:integer|min_hei:double +10001 |36174 |1.56 +10002 |36174 |1.56 +10003 |36174 |1.56 +; + + +commonFilterExtractionWithAliasAndOriginalNeedingNormalization +required_capability: inlinestats_v10 +from employees +| eval eno = emp_no +| inlinestats min_sal = min(salary) where eno <= 10010, + min_hei = min(height) where emp_no <= 10010, + max_hei = max(height) where 10010 >= emp_no +| keep eno, min*, max* +| sort eno +| limit 5 +; + + eno:integer |min_sal:integer|min_hei:double |max_hei:double +10001 |36174 |1.56 |2.1 +10002 |36174 |1.56 |2.1 +10003 |36174 |1.56 |2.1 +10004 |36174 |1.56 |2.1 +10005 |36174 |1.56 |2.1 +; + +commonFilterExtractionWithAliasAndOriginalNeedingNormalizationAndSimplification +required_capability: inlinestats_v10 +from employees +| eval eno = emp_no +| inlinestats min_sal = min(salary) where eno <= 10010, + min_hei = min(height) where not (emp_no > 10010), + max_hei = max(height) where 10010 >= emp_no +| keep eno, min*, max* +| sort eno +| limit 5 +; + + eno:integer |min_sal:integer|min_hei:double |max_hei:double +10001 |36174 |1.56 |2.1 +10002 |36174 |1.56 |2.1 +10003 |36174 |1.56 |2.1 +10004 |36174 |1.56 |2.1 +10005 |36174 |1.56 |2.1 +; + +filterIsAlwaysTrue +required_capability: inlinestats_v10 +FROM employees +| inlinestats max = max(salary) WHERE salary > 0 +| keep max, salary, emp_no +| sort emp_no +| limit 3 +; + + max:integer |salary:integer | emp_no:integer +74999 |57305 |10001 +74999 |56371 |10002 +74999 |61805 |10003 +; + +filterIsAlwaysFalse +required_capability: inlinestats_v10 +FROM employees +| inlinestats max = max(salary) WHERE first_name == "" +| sort emp_no +| keep max, first_name +| limit 10 +; + + max:integer |first_name:keyword +null |Georgi +null |Bezalel +null |Parto +null |Chirstian +null |Kyoichi +null |Anneke +null |Tzvetan +null |Saniya +null |Sumant +null |Duangkaew +; + + +filterSometimesMatches +required_capability: inlinestats_v10 +FROM employees +| inlinestats max = max(salary) WHERE first_name IS NULL +| sort emp_no +| keep max, first_name +| limit 10 +; + + max:integer |first_name:keyword +70011 |Georgi +70011 |Bezalel +70011 |Parto +70011 |Chirstian +70011 |Kyoichi +70011 |Anneke +70011 |Tzvetan +70011 |Saniya +70011 |Sumant +70011 |Duangkaew +; + +groupingFilterIsAlwaysTrue +required_capability: inlinestats_v10 +FROM employees +| MV_EXPAND job_positions +| inlinestats max = max(salary) WHERE salary > 0 BY job_positions = SUBSTRING(job_positions, 1, 1) +| SORT job_positions, emp_no +| LIMIT 4 +| keep max, salary, first_name, job_positions, emp_no +; + + max:integer |salary:integer |first_name:keyword| job_positions:keyword | emp_no:integer +74970 |57305 |Georgi |A |10001 +74970 |45797 |Duangkaew |A |10010 +74970 |31120 |Mary |A |10011 +74970 |48942 |Patricio |A |10012 +; + + +groupingFilterIsAlwaysFalse +required_capability: inlinestats_v10 +FROM employees +| MV_EXPAND job_positions +| inlinestats max = max(salary) WHERE first_name == "" BY job_positions = SUBSTRING(job_positions, 1, 1) +| SORT job_positions, emp_no +| LIMIT 4 +| keep max, salary, first_name, job_positions, emp_no +; + + max:integer |salary:integer |first_name:keyword| job_positions:keyword | emp_no:integer +null |57305 |Georgi |A |10001 +null |45797 |Duangkaew |A |10010 +null |31120 |Mary |A |10011 +null |48942 |Patricio |A |10012 +; + + +groupingFilterSometimesMatches +required_capability: inlinestats_v10 +FROM employees +| MV_EXPAND job_positions +| inlinestats max = max(salary) WHERE first_name IS NULL BY job_positions = SUBSTRING(job_positions, 1, 1) +| SORT job_positions, emp_no +| LIMIT 4 +| keep max, salary, first_name, job_positions, emp_no +; + + max:integer |salary:integer |first_name:keyword| job_positions:keyword | emp_no:integer +62233 |57305 |Georgi |A |10001 +62233 |45797 |Duangkaew |A |10010 +62233 |31120 |Mary |A |10011 +62233 |48942 |Patricio |A |10012 +; + +groupingByOrdinalsFilterIsAlwaysTrue +required_capability: inlinestats_v10 +FROM employees +| inlinestats max = max(salary) WHERE salary > 0 BY job_positions +| SORT job_positions ASC, salary DESC +| LIMIT 4 +| keep max, salary, job_positions, emp_no +; + + max:integer |salary:integer | job_positions:keyword | emp_no:integer +[74970, 74970, 74999, 74970]|74970 |[Accountant, Junior Developer, Principal Support Engineer, Purchase Manager]|10045 +[74970, 74999, 74999] |66817 |[Accountant, Principal Support Engineer, Senior Python Developer] |10094 +[74970, 74970, 65030, 71165]|61358 |[Accountant, Purchase Manager, Python Developer, Reporting Analyst] |10016 +[74970, 58121, 74970] |58121 |[Accountant, Business Analyst, Purchase Manager] |10051 +; + +groupingByOrdinalsFilterIsAlwaysFalse +required_capability: inlinestats_v10 + +FROM employees +| inlinestats max = max(salary) WHERE first_name == "" BY job_positions +| SORT job_positions DESC NULLS last, emp_no +| LIMIT 4 +| keep first_name, salary, emp_no, job_positions, max +; + +first_name:s |salary:i | emp_no:i | job_positions:s | max:i +Chirstian |36174 |10004 |[Head Human Resources, Reporting Analyst, Support Engineer, Tech Lead]|null +Anneke |60335 |10006 |[Principal Support Engineer, Senior Team Lead, Tech Lead] |null +Duangkaew |45797 |10010 |[Architect, Purchase Manager, Reporting Analyst, Tech Lead] |null +Mary |31120 |10011 |[Architect, Reporting Analyst, Senior Team Lead, Tech Lead] |null +; + +groupingByOrdinalsFilterSometimesMatches +required_capability: inlinestats_v10 + +FROM employees +| keep salary, first_name, job_positions, emp_no +| inlinestats max = max(salary) WHERE first_name IS NULL BY job_positions +| SORT emp_no +| LIMIT 4 +; + + salary:i |first_name:s | emp_no:i | max:i | job_positions:s +57305 |Georgi |10001 |[39878, 62233] |[Accountant, Senior Python Developer] +56371 |Bezalel |10002 |67492 |Senior Team Lead +61805 |Parto |10003 |70011 |null +36174 |Chirstian |10004 |[35222, 67492] |[Head Human Resources, Reporting Analyst, Support Engineer, Tech Lead] +; + +stdDevFilter +required_capability: inlinestats_v10 +FROM employees +| inlinestats greater_than = STD_DEV(salary_change) WHERE languages > 3 +, less_than = STD_DEV(salary_change) WHERE languages <= 3 +, salary = STD_DEV(salary * 2) +, count = COUNT(*) BY gender +| keep emp_no, gender, languages, *than, salary, count +| SORT emp_no asc +| limit 10 +; + + emp_no:integer|gender:keyword |languages:integer|greater_than:double|less_than:double | salary:double | count:long +10001 |M |2 |6.975232333891946 |6.604807075547775|26171.331109641273|57 +10002 |F |5 |6.4543266953142835 |7.57786788789264 |29045.770666969744|33 +10003 |M |4 |6.975232333891946 |6.604807075547775|26171.331109641273|57 +10004 |M |5 |6.975232333891946 |6.604807075547775|26171.331109641273|57 +10005 |M |1 |6.975232333891946 |6.604807075547775|26171.331109641273|57 +10006 |F |3 |6.4543266953142835 |7.57786788789264 |29045.770666969744|33 +10007 |F |4 |6.4543266953142835 |7.57786788789264 |29045.770666969744|33 +10008 |M |2 |6.975232333891946 |6.604807075547775|26171.331109641273|57 +10009 |F |1 |6.4543266953142835 |7.57786788789264 |29045.770666969744|33 +10010 |null |4 |6.949207097931448 |7.127229475750027|27921.220736207077|10 +; + +twoConsecutiveInlinestatsWithFalseFilters +required_capability: inlinestats_v10 +from employees +| keep emp_no +| sort emp_no +| limit 3 +| inlinestats count = count(*) where false +| inlinestats cc = count_distinct(emp_no) where false +; + + emp_no:i | count:l | cc:l +10001 |0 |0 +10002 |0 |0 +10003 |0 |0 +; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java index 94c6c415ed952..871e24f69470b 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java @@ -972,7 +972,7 @@ public enum Cap { * Fixes a series of issues with inlinestats which had an incomplete implementation after lookup and inlinestats * were refactored. */ - INLINESTATS_V9(EsqlPlugin.INLINESTATS_FEATURE_FLAG), + INLINESTATS_V10(EsqlPlugin.INLINESTATS_FEATURE_FLAG), /** * Support partial_results diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/ReplaceStatsFilteredAggWithEval.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/ReplaceStatsFilteredAggWithEval.java index a7e56a5f25fc8..fcc59b4268348 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/ReplaceStatsFilteredAggWithEval.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/ReplaceStatsFilteredAggWithEval.java @@ -14,6 +14,7 @@ import org.elasticsearch.xpack.esql.core.expression.Literal; import org.elasticsearch.xpack.esql.core.expression.NamedExpression; import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.util.Holder; import org.elasticsearch.xpack.esql.expression.function.aggregate.AggregateFunction; import org.elasticsearch.xpack.esql.expression.function.aggregate.Count; import org.elasticsearch.xpack.esql.expression.function.aggregate.CountDistinct; @@ -21,6 +22,7 @@ import org.elasticsearch.xpack.esql.plan.logical.Eval; import org.elasticsearch.xpack.esql.plan.logical.LogicalPlan; import org.elasticsearch.xpack.esql.plan.logical.Project; +import org.elasticsearch.xpack.esql.plan.logical.join.InlineJoin; import org.elasticsearch.xpack.esql.plan.logical.local.LocalRelation; import org.elasticsearch.xpack.esql.plan.logical.local.LocalSupplier; import org.elasticsearch.xpack.esql.planner.PlannerUtils; @@ -31,49 +33,101 @@ /** * Replaces an aggregation function having a false/null filter with an EVAL node. *
- * ... | STATS x = someAgg(y) WHERE FALSE {BY z} | ...
+ * ... | STATS/INLINESTATS x = someAgg(y) WHERE FALSE {BY z} | ...
* =>
- * ... | STATS x = someAgg(y) {BY z} > | EVAL x = NULL | KEEP x{, z} | ...
+ * ... | STATS/INLINESTATS x = someAgg(y) {BY z} > | EVAL x = NULL | KEEP x{, z} | ...
*
+ *
+ * This rule is applied to both STATS' {@link Aggregate} and {@link InlineJoin} right-hand side {@link Aggregate} plans.
+ * The logic is common for both, but the handling of the {@link InlineJoin} is slightly different when it comes to pruning
+ * its right-hand side {@link Aggregate}.
*/
-public class ReplaceStatsFilteredAggWithEval extends OptimizerRules.OptimizerRule{@code
- * Limit[1000[INTEGER]]
- * \_LocalRelation[[sum(salary) where false{r}#26],[ConstantNullBlock[positions=1]]]
- * }
- */
- public void testReplaceStatsFilteredAggWithEvalSingleAgg() {
- var plan = plan("""
- from test
- | stats sum(salary) where false
- """);
-
- var project = as(plan, Limit.class);
- var source = as(project.child(), LocalRelation.class);
- assertThat(Expressions.names(source.output()), contains("sum(salary) where false"));
- Block[] blocks = source.supplier().get();
- assertThat(blocks.length, is(1));
- assertThat(blocks[0].getPositionCount(), is(1));
- assertTrue(blocks[0].areAllValuesNull());
- }
-
- /**
- * {@code
- * Project[[sum(salary) + 1 where false{r}#68]]
- * \_Eval[[$$SUM$sum(salary)_+_1$0{r$}#79 + 1[INTEGER] AS sum(salary) + 1 where false]]
- * \_Limit[1000[INTEGER]]
- * \_LocalRelation[[$$SUM$sum(salary)_+_1$0{r$}#79],[ConstantNullBlock[positions=1]]]
- * }
- */
- public void testReplaceStatsFilteredAggWithEvalSingleAggWithExpression() {
- var plan = plan("""
- from test
- | stats sum(salary) + 1 where false
- """);
-
- var project = as(plan, Project.class);
- assertThat(Expressions.names(project.projections()), contains("sum(salary) + 1 where false"));
-
- var eval = as(project.child(), Eval.class);
- assertThat(eval.fields().size(), is(1));
- var alias = as(eval.fields().getFirst(), Alias.class);
- assertThat(alias.name(), is("sum(salary) + 1 where false"));
- var add = as(alias.child(), Add.class);
- var literal = as(add.right(), Literal.class);
- assertThat(literal.value(), is(1));
-
- var limit = as(eval.child(), Limit.class);
- var source = as(limit.child(), LocalRelation.class);
-
- Block[] blocks = source.supplier().get();
- assertThat(blocks.length, is(1));
- assertThat(blocks[0].getPositionCount(), is(1));
- assertTrue(blocks[0].areAllValuesNull());
- }
-
- /**
- * {@code
- * Project[[sum(salary) + 1 where false{r}#4, sum(salary) + 2{r}#6, emp_no{f}#7]]
- * \_Eval[[null[LONG] AS sum(salary) + 1 where false, $$SUM$sum(salary)_+_2$1{r$}#18 + 2[INTEGER] AS sum(salary) + 2]]
- * \_Limit[1000[INTEGER]]
- * \_Aggregate[STANDARD,[emp_no{f}#7],[SUM(salary{f}#12,true[BOOLEAN]) AS $$SUM$sum(salary)_+_2$1, emp_no{f}#7]]
- * \_EsRelation[test][_meta_field{f}#13, emp_no{f}#7, first_name{f}#8, ge..]
- * }
- */
- public void testReplaceStatsFilteredAggWithEvalMixedFilterAndNoFilter() {
- var plan = plan("""
- from test
- | stats sum(salary) + 1 where false,
- sum(salary) + 2
- by emp_no
- """);
-
- var project = as(plan, Project.class);
- assertThat(Expressions.names(project.projections()), contains("sum(salary) + 1 where false", "sum(salary) + 2", "emp_no"));
- var eval = as(project.child(), Eval.class);
- assertThat(eval.fields().size(), is(2));
-
- var alias = as(eval.fields().getFirst(), Alias.class);
- assertTrue(alias.child().foldable());
- assertThat(alias.child().fold(FoldContext.small()), nullValue());
- assertThat(alias.child().dataType(), is(LONG));
-
- alias = as(eval.fields().getLast(), Alias.class);
- assertThat(Expressions.name(alias.child()), containsString("sum(salary) + 2"));
-
- var limit = as(eval.child(), Limit.class);
- var aggregate = as(limit.child(), Aggregate.class);
- var source = as(aggregate.child(), EsRelation.class);
- }
-
- /**
- * {@code
- * Project[[sum(salary) + 1 where false{r}#3, sum(salary) + 3{r}#5, sum(salary) + 2 where null{r}#7,
- * sum(salary) + 4 where not true{r}#9]]
- * \_Eval[[null[LONG] AS sum(salary) + 1 where false#3, $$SUM$sum(salary)_+_3$1{r$}#22 + 3[INTEGER] AS sum(salary) + 3#5
- * , null[LONG] AS sum(salary) + 2 where null#7, null[LONG] AS sum(salary) + 4 where not true#9]]
- * \_Limit[1000[INTEGER],false]
- * \_Aggregate[[],[SUM(salary{f}#15,true[BOOLEAN],compensated[KEYWORD]) AS $$SUM$sum(salary)_+_3$1#22]]
- * \_EsRelation[test][_meta_field{f}#16, emp_no{f}#10, first_name{f}#11, ..]
- * }
- *
- */
- public void testReplaceStatsFilteredAggWithEvalFilterFalseAndNull() {
- var plan = plan("""
- from test
- | stats sum(salary) + 1 where false,
- sum(salary) + 3,
- sum(salary) + 2 where null,
- sum(salary) + 4 where not true
- """);
-
- var project = as(plan, Project.class);
- assertThat(
- Expressions.names(project.projections()),
- contains("sum(salary) + 1 where false", "sum(salary) + 3", "sum(salary) + 2 where null", "sum(salary) + 4 where not true")
- );
- var eval = as(project.child(), Eval.class);
- assertThat(eval.fields().size(), is(4));
-
- var alias = as(eval.fields().getFirst(), Alias.class);
- assertTrue(alias.child().foldable());
- assertThat(alias.child().fold(FoldContext.small()), nullValue());
- assertThat(alias.child().dataType(), is(LONG));
-
- alias = as(eval.fields().get(0), Alias.class);
- assertThat(Expressions.name(alias.child()), containsString("sum(salary) + 1"));
-
- alias = as(eval.fields().get(1), Alias.class);
- assertThat(Expressions.name(alias.child()), containsString("sum(salary) + 3"));
-
- alias = as(eval.fields().get(2), Alias.class);
- assertThat(Expressions.name(alias.child()), containsString("sum(salary) + 2"));
-
- alias = as(eval.fields().get(3), Alias.class);
- assertThat(Expressions.name(alias.child()), containsString("sum(salary) + 4"));
-
- alias = as(eval.fields().getLast(), Alias.class);
- assertTrue(alias.child().foldable());
- assertThat(alias.child().fold(FoldContext.small()), nullValue());
- assertThat(alias.child().dataType(), is(LONG));
-
- var limit = as(eval.child(), Limit.class);
- var aggregate = as(limit.child(), Aggregate.class);
- var source = as(aggregate.child(), EsRelation.class);
- }
-
- /*
- * Limit[1000[INTEGER]]
- * \_LocalRelation[[count(salary) where false{r}#3],[LongVectorBlock[vector=ConstantLongVector[positions=1, value=0]]]]
- */
- public void testReplaceStatsFilteredAggWithEvalNotTrue() {
- var plan = plan("""
- from test
- | stats count(salary) where not true
- """);
-
- var limit = as(plan, Limit.class);
- var source = as(limit.child(), LocalRelation.class);
- assertThat(Expressions.names(source.output()), contains("count(salary) where not true"));
- Block[] blocks = source.supplier().get();
- assertThat(blocks.length, is(1));
- var block = as(blocks[0], LongVectorBlock.class);
- assertThat(block.getPositionCount(), is(1));
- assertThat(block.asVector().getLong(0), is(0L));
- }
-
- /*
- * Limit[1000[INTEGER],false]
- * \_Aggregate[[],[COUNT(salary{f}#10,true[BOOLEAN]) AS m1#4]]
- * \_EsRelation[test][_meta_field{f}#11, emp_no{f}#5, first_name{f}#6, ge..]
- */
- public void testReplaceStatsFilteredAggWithEvalNotFalse() {
- var plan = plan("""
- from test
- | stats m1 = count(salary) where not false
- """);
- var limit = as(plan, Limit.class);
- var aggregate = as(limit.child(), Aggregate.class);
- assertEquals(1, aggregate.aggregates().size());
- assertEquals(1, aggregate.aggregates().get(0).children().size());
- assertTrue(aggregate.aggregates().get(0).children().get(0) instanceof Count);
- assertEquals("true", (((Count) aggregate.aggregates().get(0).children().get(0)).filter().toString()));
- assertThat(Expressions.names(aggregate.aggregates()), contains("m1"));
- var source = as(aggregate.child(), EsRelation.class);
- }
-
- /**
- * {@code
- * Limit[1000[INTEGER]]
- * \_LocalRelation[[count(salary) where false{r}#3],[LongVectorBlock[vector=ConstantLongVector[positions=1, value=0]]]]
- * }
- */
- public void testReplaceStatsFilteredAggWithEvalCount() {
- var plan = plan("""
- from test
- | stats count(salary) where false
- """);
-
- var limit = as(plan, Limit.class);
- var source = as(limit.child(), LocalRelation.class);
- assertThat(Expressions.names(source.output()), contains("count(salary) where false"));
- Block[] blocks = source.supplier().get();
- assertThat(blocks.length, is(1));
- var block = as(blocks[0], LongVectorBlock.class);
- assertThat(block.getPositionCount(), is(1));
- assertThat(block.asVector().getLong(0), is(0L));
- }
-
- /**
- * {@code
- * Project[[count_distinct(salary + 2) + 3 where false{r}#3]]
- * \_Eval[[$$COUNTDISTINCT$count_distinct(>$0{r$}#15 + 3[INTEGER] AS count_distinct(salary + 2) + 3 where false]]
- * \_Limit[1000[INTEGER]]
- * \_LocalRelation[[$$COUNTDISTINCT$count_distinct(>$0{r$}#15],[LongVectorBlock[vector=ConstantLongVector[positions=1, value=0]]]]
- * }
- */
- public void testReplaceStatsFilteredAggWithEvalCountDistinctInExpression() {
- var plan = plan("""
- from test
- | stats count_distinct(salary + 2) + 3 where false
- """);
-
- var project = as(plan, Project.class);
- assertThat(Expressions.names(project.projections()), contains("count_distinct(salary + 2) + 3 where false"));
-
- var eval = as(project.child(), Eval.class);
- assertThat(eval.fields().size(), is(1));
- var alias = as(eval.fields().getFirst(), Alias.class);
- assertThat(alias.name(), is("count_distinct(salary + 2) + 3 where false"));
- var add = as(alias.child(), Add.class);
- var literal = as(add.right(), Literal.class);
- assertThat(literal.value(), is(3));
-
- var limit = as(eval.child(), Limit.class);
- var source = as(limit.child(), LocalRelation.class);
-
- Block[] blocks = source.supplier().get();
- assertThat(blocks.length, is(1));
- var block = as(blocks[0], LongVectorBlock.class);
- assertThat(block.getPositionCount(), is(1));
- assertThat(block.asVector().getLong(0), is(0L));
- }
-
- /**
- * {@code
- * Project[[max{r}#91, max_a{r}#94, min{r}#97, min_a{r}#100, emp_no{f}#101]]
- * \_Eval[[null[INTEGER] AS max_a, null[INTEGER] AS min_a]]
- * \_Limit[1000[INTEGER]]
- * \_Aggregate[STANDARD,[emp_no{f}#101],[MAX(salary{f}#106,true[BOOLEAN]) AS max, MIN(salary{f}#106,true[BOOLEAN]) AS min, emp_
- * no{f}#101]]
- * \_EsRelation[test][_meta_field{f}#107, emp_no{f}#101, first_name{f}#10..]
- * }
- */
- public void testReplaceStatsFilteredAggWithEvalSameAggWithAndWithoutFilter() {
- var plan = plan("""
- from test
- | stats max = max(salary), max_a = max(salary) where null,
- min = min(salary), min_a = min(salary) where to_string(null) == "abc"
- by emp_no
- """);
-
- var project = as(plan, Project.class);
- assertThat(Expressions.names(project.projections()), contains("max", "max_a", "min", "min_a", "emp_no"));
- var eval = as(project.child(), Eval.class);
- assertThat(eval.fields().size(), is(2));
-
- var alias = as(eval.fields().getFirst(), Alias.class);
- assertThat(Expressions.name(alias), containsString("max_a"));
- assertTrue(alias.child().foldable());
- assertThat(alias.child().fold(FoldContext.small()), nullValue());
- assertThat(alias.child().dataType(), is(INTEGER));
-
- alias = as(eval.fields().getLast(), Alias.class);
- assertThat(Expressions.name(alias), containsString("min_a"));
- assertTrue(alias.child().foldable());
- assertThat(alias.child().fold(FoldContext.small()), nullValue());
- assertThat(alias.child().dataType(), is(INTEGER));
-
- var limit = as(eval.child(), Limit.class);
-
- var aggregate = as(limit.child(), Aggregate.class);
- assertThat(Expressions.names(aggregate.aggregates()), contains("max", "min", "emp_no"));
-
- var source = as(aggregate.child(), EsRelation.class);
- }
-
- /**
- * {@code
- * Limit[1000[INTEGER]]
- * \_LocalRelation[[count{r}#7],[LongVectorBlock[vector=ConstantLongVector[positions=1, value=0]]]]
- * }
- */
- @AwaitsFix(bugUrl = "https://github.com/elastic/elasticsearch/issues/100634") // i.e. PropagateEvalFoldables applicability to Aggs
- public void testReplaceStatsFilteredAggWithEvalFilterUsingEvaledValue() {
- var plan = plan("""
- from test
- | eval my_length = length(concat(first_name, null))
- | stats count = count(my_length) where my_length > 0
- """);
-
- var limit = as(plan, Limit.class);
- var source = as(limit.child(), LocalRelation.class);
- assertThat(Expressions.names(source.output()), contains("count"));
- Block[] blocks = source.supplier().get();
- assertThat(blocks.length, is(1));
- var block = as(blocks[0], LongVectorBlock.class);
- assertThat(block.getPositionCount(), is(1));
- assertThat(block.asVector().getLong(0), is(0L));
- }
-
- /**
- *
- * {@code
- * Project[[c{r}#67, emp_no{f}#68]]
- * \_Eval[[0[LONG] AS c]]
- * \_Limit[1000[INTEGER]]
- * \_Aggregate[STANDARD,[emp_no{f}#68],[emp_no{f}#68]]
- * \_EsRelation[test][_meta_field{f}#74, emp_no{f}#68, first_name{f}#69, ..]
- * }
- */
- public void testReplaceStatsFilteredAggWithEvalSingleAggWithGroup() {
- var plan = plan("""
- from test
- | stats c = count(emp_no) where false
- by emp_no
- """);
-
- var project = as(plan, Project.class);
- assertThat(Expressions.names(project.projections()), contains("c", "emp_no"));
-
- var eval = as(project.child(), Eval.class);
- assertThat(eval.fields().size(), is(1));
- var alias = as(eval.fields().getFirst(), Alias.class);
- assertThat(Expressions.name(alias), containsString("c"));
-
- var limit = as(eval.child(), Limit.class);
-
- var aggregate = as(limit.child(), Aggregate.class);
- assertThat(Expressions.names(aggregate.aggregates()), contains("emp_no"));
-
- var source = as(aggregate.child(), EsRelation.class);
- }
-
public void testExtractStatsCommonFilter() {
var plan = plan("""
from test
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/PropagateInlineEvalsTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/PropagateInlineEvalsTests.java
index 3b183c803ecd1..b9a469edae907 100644
--- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/PropagateInlineEvalsTests.java
+++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/PropagateInlineEvalsTests.java
@@ -83,7 +83,7 @@ public static void init() {
* \_StubRelation[[emp_no{f}#11, languages{f}#14, gender{f}#13, y{r}#10]]
*/
public void testGroupingAliasingMoved_To_LeftSideOfJoin() {
- assumeTrue("Requires INLINESTATS", EsqlCapabilities.Cap.INLINESTATS_V9.isEnabled());
+ assumeTrue("Requires INLINESTATS", EsqlCapabilities.Cap.INLINESTATS_V10.isEnabled());
var plan = plan("""
from test
| keep emp_no, languages, gender
@@ -126,7 +126,7 @@ public void testGroupingAliasingMoved_To_LeftSideOfJoin() {
* {r}#21]]
*/
public void testGroupingAliasingMoved_To_LeftSideOfJoin_WithExpression() {
- assumeTrue("Requires INLINESTATS", EsqlCapabilities.Cap.INLINESTATS_V9.isEnabled());
+ assumeTrue("Requires INLINESTATS", EsqlCapabilities.Cap.INLINESTATS_V10.isEnabled());
var plan = plan("""
from test
| keep emp_no, languages, gender, last_name, first_name
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/ReplaceStatsFilteredAggWithEvalTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/ReplaceStatsFilteredAggWithEvalTests.java
new file mode 100644
index 0000000000000..464c12a81f97d
--- /dev/null
+++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/ReplaceStatsFilteredAggWithEvalTests.java
@@ -0,0 +1,774 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+package org.elasticsearch.xpack.esql.optimizer.rules.logical;
+
+import org.elasticsearch.compute.data.Block;
+import org.elasticsearch.compute.data.LongVectorBlock;
+import org.elasticsearch.xpack.esql.core.expression.Alias;
+import org.elasticsearch.xpack.esql.core.expression.Expressions;
+import org.elasticsearch.xpack.esql.core.expression.FoldContext;
+import org.elasticsearch.xpack.esql.core.expression.Literal;
+import org.elasticsearch.xpack.esql.expression.function.aggregate.Count;
+import org.elasticsearch.xpack.esql.expression.predicate.operator.arithmetic.Add;
+import org.elasticsearch.xpack.esql.optimizer.AbstractLogicalPlanOptimizerTests;
+import org.elasticsearch.xpack.esql.plan.logical.Aggregate;
+import org.elasticsearch.xpack.esql.plan.logical.EsRelation;
+import org.elasticsearch.xpack.esql.plan.logical.Eval;
+import org.elasticsearch.xpack.esql.plan.logical.Limit;
+import org.elasticsearch.xpack.esql.plan.logical.Project;
+import org.elasticsearch.xpack.esql.plan.logical.TopN;
+import org.elasticsearch.xpack.esql.plan.logical.join.InlineJoin;
+import org.elasticsearch.xpack.esql.plan.logical.join.StubRelation;
+import org.elasticsearch.xpack.esql.plan.logical.local.EsqlProject;
+import org.elasticsearch.xpack.esql.plan.logical.local.LocalRelation;
+
+import static org.elasticsearch.test.ListMatcher.matchesList;
+import static org.elasticsearch.test.MapMatcher.assertMap;
+import static org.elasticsearch.xpack.esql.EsqlTestUtils.as;
+import static org.elasticsearch.xpack.esql.core.type.DataType.INTEGER;
+import static org.elasticsearch.xpack.esql.core.type.DataType.LONG;
+import static org.hamcrest.Matchers.contains;
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.nullValue;
+import static org.hamcrest.Matchers.startsWith;
+
+public class ReplaceStatsFilteredAggWithEvalTests extends AbstractLogicalPlanOptimizerTests {
+
+ /**
+ * {@code
+ * Limit[1000[INTEGER]]
+ * \_LocalRelation[[sum(salary) where false{r}#26],[ConstantNullBlock[positions=1]]]
+ * }
+ */
+ public void testReplaceStatsFilteredAggWithEvalSingleAgg() {
+ var plan = plan("""
+ from test
+ | stats sum(salary) where false
+ """);
+
+ var project = as(plan, Limit.class);
+ var source = as(project.child(), LocalRelation.class);
+ assertThat(Expressions.names(source.output()), contains("sum(salary) where false"));
+ Block[] blocks = source.supplier().get();
+ assertThat(blocks.length, is(1));
+ assertThat(blocks[0].getPositionCount(), is(1));
+ assertTrue(blocks[0].areAllValuesNull());
+ }
+
+ /**
+ * {@code
+ * Project[[sum(salary) + 1 where false{r}#68]]
+ * \_Eval[[$$SUM$sum(salary)_+_1$0{r$}#79 + 1[INTEGER] AS sum(salary) + 1 where false]]
+ * \_Limit[1000[INTEGER]]
+ * \_LocalRelation[[$$SUM$sum(salary)_+_1$0{r$}#79],[ConstantNullBlock[positions=1]]]
+ * }
+ */
+ public void testReplaceStatsFilteredAggWithEvalSingleAggWithExpression() {
+ var plan = plan("""
+ from test
+ | stats sum(salary) + 1 where false
+ """);
+
+ var project = as(plan, Project.class);
+ assertThat(Expressions.names(project.projections()), contains("sum(salary) + 1 where false"));
+
+ var eval = as(project.child(), Eval.class);
+ assertThat(eval.fields().size(), is(1));
+ var alias = as(eval.fields().getFirst(), Alias.class);
+ assertThat(alias.name(), is("sum(salary) + 1 where false"));
+ var add = as(alias.child(), Add.class);
+ var literal = as(add.right(), Literal.class);
+ assertThat(literal.value(), is(1));
+
+ var limit = as(eval.child(), Limit.class);
+ var source = as(limit.child(), LocalRelation.class);
+
+ Block[] blocks = source.supplier().get();
+ assertThat(blocks.length, is(1));
+ assertThat(blocks[0].getPositionCount(), is(1));
+ assertTrue(blocks[0].areAllValuesNull());
+ }
+
+ /**
+ * {@code
+ * Project[[sum(salary) + 1 where false{r}#4, sum(salary) + 2{r}#6, emp_no{f}#7]]
+ * \_Eval[[null[LONG] AS sum(salary) + 1 where false, $$SUM$sum(salary)_+_2$1{r$}#18 + 2[INTEGER] AS sum(salary) + 2]]
+ * \_Limit[1000[INTEGER]]
+ * \_Aggregate[STANDARD,[emp_no{f}#7],[SUM(salary{f}#12,true[BOOLEAN]) AS $$SUM$sum(salary)_+_2$1, emp_no{f}#7]]
+ * \_EsRelation[test][_meta_field{f}#13, emp_no{f}#7, first_name{f}#8, ge..]
+ * }
+ */
+ public void testReplaceStatsFilteredAggWithEvalMixedFilterAndNoFilter() {
+ var plan = plan("""
+ from test
+ | stats sum(salary) + 1 where false,
+ sum(salary) + 2
+ by emp_no
+ """);
+
+ var project = as(plan, Project.class);
+ assertThat(Expressions.names(project.projections()), contains("sum(salary) + 1 where false", "sum(salary) + 2", "emp_no"));
+ var eval = as(project.child(), Eval.class);
+ assertThat(eval.fields().size(), is(2));
+
+ var alias = as(eval.fields().getFirst(), Alias.class);
+ assertTrue(alias.child().foldable());
+ assertThat(alias.child().fold(FoldContext.small()), nullValue());
+ assertThat(alias.child().dataType(), is(LONG));
+
+ alias = as(eval.fields().getLast(), Alias.class);
+ assertThat(Expressions.name(alias.child()), containsString("sum(salary) + 2"));
+
+ var limit = as(eval.child(), Limit.class);
+ var aggregate = as(limit.child(), Aggregate.class);
+ var source = as(aggregate.child(), EsRelation.class);
+ }
+
+ /**
+ * {@code
+ * Project[[sum(salary) + 1 where false{r}#3, sum(salary) + 3{r}#5, sum(salary) + 2 where null{r}#7,
+ * sum(salary) + 4 where not true{r}#9]]
+ * \_Eval[[null[LONG] AS sum(salary) + 1 where false#3, $$SUM$sum(salary)_+_3$1{r$}#22 + 3[INTEGER] AS sum(salary) + 3#5
+ * , null[LONG] AS sum(salary) + 2 where null#7, null[LONG] AS sum(salary) + 4 where not true#9]]
+ * \_Limit[1000[INTEGER],false]
+ * \_Aggregate[[],[SUM(salary{f}#15,true[BOOLEAN],compensated[KEYWORD]) AS $$SUM$sum(salary)_+_3$1#22]]
+ * \_EsRelation[test][_meta_field{f}#16, emp_no{f}#10, first_name{f}#11, ..]
+ * }
+ *
+ */
+ public void testReplaceStatsFilteredAggWithEvalFilterFalseAndNull() {
+ var plan = plan("""
+ from test
+ | stats sum(salary) + 1 where false,
+ sum(salary) + 3,
+ sum(salary) + 2 where null,
+ sum(salary) + 4 where not true
+ """);
+
+ var project = as(plan, Project.class);
+ assertThat(
+ Expressions.names(project.projections()),
+ contains("sum(salary) + 1 where false", "sum(salary) + 3", "sum(salary) + 2 where null", "sum(salary) + 4 where not true")
+ );
+ var eval = as(project.child(), Eval.class);
+ assertThat(eval.fields().size(), is(4));
+
+ var alias = as(eval.fields().getFirst(), Alias.class);
+ assertTrue(alias.child().foldable());
+ assertThat(alias.child().fold(FoldContext.small()), nullValue());
+ assertThat(alias.child().dataType(), is(LONG));
+
+ alias = as(eval.fields().get(0), Alias.class);
+ assertThat(Expressions.name(alias.child()), containsString("sum(salary) + 1"));
+
+ alias = as(eval.fields().get(1), Alias.class);
+ assertThat(Expressions.name(alias.child()), containsString("sum(salary) + 3"));
+
+ alias = as(eval.fields().get(2), Alias.class);
+ assertThat(Expressions.name(alias.child()), containsString("sum(salary) + 2"));
+
+ alias = as(eval.fields().get(3), Alias.class);
+ assertThat(Expressions.name(alias.child()), containsString("sum(salary) + 4"));
+
+ alias = as(eval.fields().getLast(), Alias.class);
+ assertTrue(alias.child().foldable());
+ assertThat(alias.child().fold(FoldContext.small()), nullValue());
+ assertThat(alias.child().dataType(), is(LONG));
+
+ var limit = as(eval.child(), Limit.class);
+ var aggregate = as(limit.child(), Aggregate.class);
+ var source = as(aggregate.child(), EsRelation.class);
+ }
+
+ /*
+ * Limit[1000[INTEGER]]
+ * \_LocalRelation[[count(salary) where false{r}#3],[LongVectorBlock[vector=ConstantLongVector[positions=1, value=0]]]]
+ */
+ public void testReplaceStatsFilteredAggWithEvalNotTrue() {
+ var plan = plan("""
+ from test
+ | stats count(salary) where not true
+ """);
+
+ var limit = as(plan, Limit.class);
+ var source = as(limit.child(), LocalRelation.class);
+ assertThat(Expressions.names(source.output()), contains("count(salary) where not true"));
+ Block[] blocks = source.supplier().get();
+ assertThat(blocks.length, is(1));
+ var block = as(blocks[0], LongVectorBlock.class);
+ assertThat(block.getPositionCount(), is(1));
+ assertThat(block.asVector().getLong(0), is(0L));
+ }
+
+ /*
+ * Limit[1000[INTEGER],false]
+ * \_Aggregate[[],[COUNT(salary{f}#10,true[BOOLEAN]) AS m1#4]]
+ * \_EsRelation[test][_meta_field{f}#11, emp_no{f}#5, first_name{f}#6, ge..]
+ */
+ public void testReplaceStatsFilteredAggWithEvalNotFalse() {
+ var plan = plan("""
+ from test
+ | stats m1 = count(salary) where not false
+ """);
+ var limit = as(plan, Limit.class);
+ var aggregate = as(limit.child(), Aggregate.class);
+ assertEquals(1, aggregate.aggregates().size());
+ assertEquals(1, aggregate.aggregates().get(0).children().size());
+ assertTrue(aggregate.aggregates().get(0).children().get(0) instanceof Count);
+ assertEquals("true", (((Count) aggregate.aggregates().get(0).children().get(0)).filter().toString()));
+ assertThat(Expressions.names(aggregate.aggregates()), contains("m1"));
+ var source = as(aggregate.child(), EsRelation.class);
+ }
+
+ /**
+ * {@code
+ * Limit[1000[INTEGER]]
+ * \_LocalRelation[[count(salary) where false{r}#3],[LongVectorBlock[vector=ConstantLongVector[positions=1, value=0]]]]
+ * }
+ */
+ public void testReplaceStatsFilteredAggWithEvalCount() {
+ var plan = plan("""
+ from test
+ | stats count(salary) where false
+ """);
+
+ var limit = as(plan, Limit.class);
+ var source = as(limit.child(), LocalRelation.class);
+ assertThat(Expressions.names(source.output()), contains("count(salary) where false"));
+ Block[] blocks = source.supplier().get();
+ assertThat(blocks.length, is(1));
+ var block = as(blocks[0], LongVectorBlock.class);
+ assertThat(block.getPositionCount(), is(1));
+ assertThat(block.asVector().getLong(0), is(0L));
+ }
+
+ /**
+ * {@code
+ * Project[[count_distinct(salary + 2) + 3 where false{r}#3]]
+ * \_Eval[[$$COUNTDISTINCT$count_distinct(>$0{r$}#15 + 3[INTEGER] AS count_distinct(salary + 2) + 3 where false]]
+ * \_Limit[1000[INTEGER]]
+ * \_LocalRelation[[$$COUNTDISTINCT$count_distinct(>$0{r$}#15],[LongVectorBlock[vector=ConstantLongVector[positions=1, value=0]]]]
+ * }
+ */
+ public void testReplaceStatsFilteredAggWithEvalCountDistinctInExpression() {
+ var plan = plan("""
+ from test
+ | stats count_distinct(salary + 2) + 3 where false
+ """);
+
+ var project = as(plan, Project.class);
+ assertThat(Expressions.names(project.projections()), contains("count_distinct(salary + 2) + 3 where false"));
+
+ var eval = as(project.child(), Eval.class);
+ assertThat(eval.fields().size(), is(1));
+ var alias = as(eval.fields().getFirst(), Alias.class);
+ assertThat(alias.name(), is("count_distinct(salary + 2) + 3 where false"));
+ var add = as(alias.child(), Add.class);
+ var literal = as(add.right(), Literal.class);
+ assertThat(literal.value(), is(3));
+
+ var limit = as(eval.child(), Limit.class);
+ var source = as(limit.child(), LocalRelation.class);
+
+ Block[] blocks = source.supplier().get();
+ assertThat(blocks.length, is(1));
+ var block = as(blocks[0], LongVectorBlock.class);
+ assertThat(block.getPositionCount(), is(1));
+ assertThat(block.asVector().getLong(0), is(0L));
+ }
+
+ /**
+ * {@code
+ * Project[[max{r}#91, max_a{r}#94, min{r}#97, min_a{r}#100, emp_no{f}#101]]
+ * \_Eval[[null[INTEGER] AS max_a, null[INTEGER] AS min_a]]
+ * \_Limit[1000[INTEGER]]
+ * \_Aggregate[STANDARD,[emp_no{f}#101],[MAX(salary{f}#106,true[BOOLEAN]) AS max, MIN(salary{f}#106,true[BOOLEAN]) AS min, emp_
+ * no{f}#101]]
+ * \_EsRelation[test][_meta_field{f}#107, emp_no{f}#101, first_name{f}#10..]
+ * }
+ */
+ public void testReplaceStatsFilteredAggWithEvalSameAggWithAndWithoutFilter() {
+ var plan = plan("""
+ from test
+ | stats max = max(salary), max_a = max(salary) where null,
+ min = min(salary), min_a = min(salary) where to_string(null) == "abc"
+ by emp_no
+ """);
+
+ var project = as(plan, Project.class);
+ assertThat(Expressions.names(project.projections()), contains("max", "max_a", "min", "min_a", "emp_no"));
+ var eval = as(project.child(), Eval.class);
+ assertThat(eval.fields().size(), is(2));
+
+ var alias = as(eval.fields().getFirst(), Alias.class);
+ assertThat(Expressions.name(alias), containsString("max_a"));
+ assertTrue(alias.child().foldable());
+ assertThat(alias.child().fold(FoldContext.small()), nullValue());
+ assertThat(alias.child().dataType(), is(INTEGER));
+
+ alias = as(eval.fields().getLast(), Alias.class);
+ assertThat(Expressions.name(alias), containsString("min_a"));
+ assertTrue(alias.child().foldable());
+ assertThat(alias.child().fold(FoldContext.small()), nullValue());
+ assertThat(alias.child().dataType(), is(INTEGER));
+
+ var limit = as(eval.child(), Limit.class);
+
+ var aggregate = as(limit.child(), Aggregate.class);
+ assertThat(Expressions.names(aggregate.aggregates()), contains("max", "min", "emp_no"));
+
+ var source = as(aggregate.child(), EsRelation.class);
+ }
+
+ /**
+ * {@code
+ * Limit[1000[INTEGER]]
+ * \_LocalRelation[[count{r}#7],[LongVectorBlock[vector=ConstantLongVector[positions=1, value=0]]]]
+ * }
+ */
+ @AwaitsFix(bugUrl = "https://github.com/elastic/elasticsearch/issues/100634") // i.e. PropagateEvalFoldables applicability to Aggs
+ public void testReplaceStatsFilteredAggWithEvalFilterUsingEvaledValue() {
+ var plan = plan("""
+ from test
+ | eval my_length = length(concat(first_name, null))
+ | stats count = count(my_length) where my_length > 0
+ """);
+
+ var limit = as(plan, Limit.class);
+ var source = as(limit.child(), LocalRelation.class);
+ assertThat(Expressions.names(source.output()), contains("count"));
+ Block[] blocks = source.supplier().get();
+ assertThat(blocks.length, is(1));
+ var block = as(blocks[0], LongVectorBlock.class);
+ assertThat(block.getPositionCount(), is(1));
+ assertThat(block.asVector().getLong(0), is(0L));
+ }
+
+ /**
+ *
+ * {@code
+ * Project[[c{r}#67, emp_no{f}#68]]
+ * \_Eval[[0[LONG] AS c]]
+ * \_Limit[1000[INTEGER]]
+ * \_Aggregate[STANDARD,[emp_no{f}#68],[emp_no{f}#68]]
+ * \_EsRelation[test][_meta_field{f}#74, emp_no{f}#68, first_name{f}#69, ..]
+ * }
+ */
+ public void testReplaceStatsFilteredAggWithEvalSingleAggWithGroup() {
+ var plan = plan("""
+ from test
+ | stats c = count(emp_no) where false
+ by emp_no
+ """);
+
+ var project = as(plan, Project.class);
+ assertThat(Expressions.names(project.projections()), contains("c", "emp_no"));
+
+ var eval = as(project.child(), Eval.class);
+ assertThat(eval.fields().size(), is(1));
+ var alias = as(eval.fields().getFirst(), Alias.class);
+ assertThat(Expressions.name(alias), containsString("c"));
+
+ var limit = as(eval.child(), Limit.class);
+
+ var aggregate = as(limit.child(), Aggregate.class);
+ assertThat(Expressions.names(aggregate.aggregates()), contains("emp_no"));
+
+ var source = as(aggregate.child(), EsRelation.class);
+ }
+
+ /**
+ * Project[[_meta_field{f}#10, emp_no{f}#4, first_name{f}#5, gender{f}#6, hire_date{f}#11, job{f}#12, job.raw{f}#13, lang
+ * uages{f}#7, last_name{f}#8, long_noidx{f}#14, salary{f}#9, sum(salary) where false{r}#3]]
+ * \_Eval[[null[LONG] AS sum(salary) where false#3]]
+ * \_Limit[1000[INTEGER],false]
+ * \_EsRelation[test][_meta_field{f}#10, emp_no{f}#4, first_name{f}#5, ge..]
+ */
+ public void testReplaceInlinestatsFilteredAggWithEvalSingleAgg() {
+ var plan = plan("""
+ from test
+ | inlinestats sum(salary) where false
+ """);
+
+ var project = as(plan, Project.class);
+ assertMap(
+ Expressions.names(project.projections()).stream().map(Object::toString).toList(),
+ matchesList().item(startsWith("_meta_field"))
+ .item(startsWith("emp_no"))
+ .item(startsWith("first_name"))
+ .item(startsWith("gender"))
+ .item(startsWith("hire_date"))
+ .item(startsWith("job"))
+ .item(startsWith("job.raw"))
+ .item(startsWith("languages"))
+ .item(startsWith("last_name"))
+ .item(startsWith("long_noidx"))
+ .item(startsWith("salary"))
+ .item(containsString("sum(salary) where false"))
+ );
+ var eval = as(project.child(), Eval.class);
+ assertThat(eval.fields().size(), is(1));
+ var alias = as(eval.fields().getFirst(), Alias.class);
+ assertThat(Expressions.name(alias), containsString("sum(salary) where false"));
+ assertTrue(alias.child().foldable());
+ assertThat(alias.child().fold(FoldContext.small()), nullValue());
+ assertThat(alias.child().dataType(), is(LONG));
+ var limit = as(eval.child(), Limit.class);
+ as(limit.child(), EsRelation.class);
+ }
+
+ /**
+ * Project[[_meta_field{f}#10, emp_no{f}#4, first_name{f}#5, gender{f}#6, hire_date{f}#11, job{f}#12, job.raw{f}#13, lang
+ * uages{f}#7, last_name{f}#8, long_noidx{f}#14, salary{f}#9, sum(salary) + 1 where false{r}#3]]
+ * \_Eval[[null[LONG] AS sum(salary) + 1 where false#3]]
+ * \_Limit[1000[INTEGER],false]
+ * \_EsRelation[test][_meta_field{f}#10, emp_no{f}#4, first_name{f}#5, ge..]
+ */
+ public void testReplaceInlinestatsFilteredAggWithEvalSingleAggWithExpression() {
+ var plan = plan("""
+ from test
+ | inlinestats sum(salary) + 1 where false
+ """);
+
+ var project = as(plan, Project.class);
+ assertMap(
+ Expressions.names(project.projections()).stream().map(Object::toString).toList(),
+ matchesList().item(startsWith("_meta_field"))
+ .item(startsWith("emp_no"))
+ .item(startsWith("first_name"))
+ .item(startsWith("gender"))
+ .item(startsWith("hire_date"))
+ .item(startsWith("job"))
+ .item(startsWith("job.raw"))
+ .item(startsWith("languages"))
+ .item(startsWith("last_name"))
+ .item(startsWith("long_noidx"))
+ .item(startsWith("salary"))
+ .item(containsString("sum(salary) + 1 where false"))
+ );
+ var eval = as(project.child(), Eval.class);
+ assertThat(eval.fields().size(), is(1));
+ var alias = as(eval.fields().getFirst(), Alias.class);
+ assertThat(Expressions.name(alias), containsString("sum(salary) + 1 where false"));
+ assertTrue(alias.child().foldable());
+ assertThat(alias.child().fold(FoldContext.small()), nullValue());
+ assertThat(alias.child().dataType(), is(LONG));
+ var limit = as(eval.child(), Limit.class);
+ as(limit.child(), EsRelation.class);
+ }
+
+ /**
+ * Limit[1000[INTEGER],true]
+ * \_InlineJoin[LEFT,[emp_no{f}#9],[emp_no{f}#9],[emp_no{r}#9]]
+ * |_EsqlProject[[salary{f}#14, emp_no{f}#9]]
+ * | \_Limit[1000[INTEGER],false]
+ * | \_EsRelation[test][_meta_field{f}#15, emp_no{f}#9, first_name{f}#10, g..]
+ * \_Project[[sum(salary) 1 where false{r}#5, sum(salary) 2{r}#7, emp_no{f}#9]]
+ * \_Eval[[null[LONG] AS sum(salary) 1 where false#5, $$SUM$sum(salary)_ _2$1{r$}#21 2[INTEGER] AS sum(salary) 2#7]]
+ * \_Aggregate[[emp_no{f}#9],[SUM(salary{f}#14,true[BOOLEAN],compensated[KEYWORD]) AS $$SUM$sum(salary)_ _2$1#21, emp_no{f}#9]]
+ * \_StubRelation[[salary{f}#14, emp_no{f}#9]]
+ */
+ public void testReplaceInlinestatsFilteredAggWithEvalMixedFilterAndNoFilter() {
+ var plan = plan("""
+ from test
+ | keep salary, emp_no
+ | inlinestats sum(salary) + 1 where false,
+ sum(salary) + 2
+ by emp_no
+ """);
+
+ var limit = as(plan, Limit.class);
+ var ij = as(limit.child(), InlineJoin.class);
+ var left = as(ij.left(), EsqlProject.class);
+ assertThat(Expressions.names(left.projections()), contains("salary", "emp_no"));
+ limit = as(left.child(), Limit.class);
+ as(limit.child(), EsRelation.class);
+ var right = as(ij.right(), Project.class);
+ assertMap(
+ Expressions.names(right.projections()).stream().map(Object::toString).toList(),
+ matchesList().item(startsWith("sum(salary) + 1 where false")).item(startsWith("sum(salary) + 2")).item(startsWith("emp_no"))
+ );
+ var eval = as(right.child(), Eval.class);
+ assertThat(eval.fields().size(), is(2));
+ var alias = as(eval.fields().getFirst(), Alias.class);
+ assertTrue(alias.child().foldable());
+ assertThat(alias.child().fold(FoldContext.small()), nullValue());
+ assertThat(alias.child().dataType(), is(LONG));
+ assertThat(Expressions.name(alias), containsString("sum(salary) + 1 where false"));
+ alias = as(eval.fields().get(1), Alias.class);
+ assertFalse(alias.child().foldable());
+ assertThat(alias.child().dataType(), is(LONG));
+ assertThat(Expressions.name(alias), containsString("sum(salary) + 2"));
+ assertThat(alias.child() instanceof Add, is(true));
+ var add = as(alias.child(), Add.class);
+ assertThat(add.left().toString(), containsString("$$SUM$sum(salary)_+_2$1"));
+ var agg = as(eval.child(), Aggregate.class);
+ assertThat(Expressions.names(agg.aggregates()), contains("$$SUM$sum(salary)_+_2$1", "emp_no"));
+ var source = as(agg.child(), StubRelation.class);
+ assertThat(Expressions.names(source.output()), contains("salary", "emp_no"));
+ }
+
+ /**
+ * Limit[1000[INTEGER],true]
+ * \_InlineJoin[LEFT,[],[],[]]
+ * |_EsqlProject[[salary{f}#16]]
+ * | \_Limit[1000[INTEGER],false]
+ * | \_EsRelation[test][_meta_field{f}#17, emp_no{f}#11, first_name{f}#12, ..]
+ * \_Project[[sum(salary) 1 where false{r}#4, sum(salary) 3{r}#6, sum(salary) 2 where null{r}#8, sum(salary) 4 wher
+ * e not true{r}#10]]
+ * \_Eval[[null[LONG] AS sum(salary) 1 where false#4, $$SUM$sum(salary)_ _3$1{r$}#23 3[INTEGER] AS sum(salary) 3#6
+ * , null[LONG] AS sum(salary) 2 where null#8, null[LONG] AS sum(salary) 4 where not true#10]]
+ * \_Aggregate[[],[SUM(salary{f}#16,true[BOOLEAN],compensated[KEYWORD]) AS $$SUM$sum(salary)_ _3$1#23]]
+ * \_StubRelation[[salary{f}#16]]
+ */
+ public void testReplaceInlinestatsFilteredAggWithEvalFilterFalseAndNull() {
+ var plan = plan("""
+ from test
+ | keep salary
+ | inlinestats sum(salary) + 1 where false,
+ sum(salary) + 3,
+ sum(salary) + 2 where null,
+ sum(salary) + 4 where not true
+ """);
+ var limit = as(plan, Limit.class);
+ var ij = as(limit.child(), InlineJoin.class);
+
+ // Check right side Project node
+ var right = as(ij.right(), Project.class);
+ assertThat(
+ Expressions.names(right.projections()),
+ contains("sum(salary) + 1 where false", "sum(salary) + 3", "sum(salary) + 2 where null", "sum(salary) + 4 where not true")
+ );
+
+ var eval = as(right.child(), Eval.class);
+ assertThat(eval.fields().size(), is(4));
+
+ var alias1 = as(eval.fields().get(0), Alias.class);
+ assertTrue(alias1.child().foldable());
+ assertThat(alias1.child().fold(FoldContext.small()), nullValue());
+
+ var alias2 = as(eval.fields().get(1), Alias.class);
+ assertFalse(alias2.child().foldable());
+
+ var alias3 = as(eval.fields().get(2), Alias.class);
+ assertTrue(alias3.child().foldable());
+ assertThat(alias3.child().fold(FoldContext.small()), nullValue());
+
+ var alias4 = as(eval.fields().get(3), Alias.class);
+ assertTrue(alias4.child().foldable());
+ assertThat(alias4.child().fold(FoldContext.small()), nullValue());
+
+ var aggregate = as(eval.child(), Aggregate.class);
+ assertThat(Expressions.names(aggregate.aggregates()), contains("$$SUM$sum(salary)_+_3$1"));
+
+ var source = as(aggregate.child(), StubRelation.class);
+ assertThat(Expressions.names(source.output()), contains("salary"));
+ }
+
+ /**
+ * EsqlProject[[emp_no{f}#6, salary{f}#11, count(salary) where not true{r}#5]]
+ * \_Eval[[0[LONG] AS count(salary) where not true#5]]
+ * \_Limit[1000[INTEGER],false]
+ * \_EsRelation[test][_meta_field{f}#12, emp_no{f}#6, first_name{f}#7, ge..]
+ */
+ public void testReplaceInlinestatsFilteredAggWithEvalNotTrue() {
+ var plan = plan("""
+ from test
+ | keep emp_no, salary
+ | inlinestats count(salary) where not true
+ """);
+
+ var project = as(plan, EsqlProject.class);
+ assertThat(Expressions.names(project.projections()), contains("emp_no", "salary", "count(salary) where not true"));
+
+ var eval = as(project.child(), Eval.class);
+ assertThat(eval.fields().size(), is(1));
+ var alias = as(eval.fields().getFirst(), Alias.class);
+ assertThat(alias.name(), is("count(salary) where not true"));
+ assertTrue(alias.child().foldable());
+ assertThat(alias.child().fold(FoldContext.small()), is(0L));
+
+ var limit = as(eval.child(), Limit.class);
+ as(limit.child(), EsRelation.class);
+ }
+
+ /**
+ * Limit[1000[INTEGER],true]
+ * \_InlineJoin[LEFT,[],[],[]]
+ * |_EsqlProject[[emp_no{f}#8, salary{f}#13, gender{f}#10]]
+ * | \_Limit[1000[INTEGER],false]
+ * | \_EsRelation[test][_meta_field{f}#14, emp_no{f}#8, first_name{f}#9, ge..]
+ * \_Aggregate[[],[COUNT(salary{f}#13,true[BOOLEAN]) AS m1#7]]
+ * \_StubRelation[[emp_no{f}#8, salary{f}#13, gender{f}#10]]
+ */
+ public void testReplaceInlinestatsFilteredAggWithEvalNotFalse() {
+ var plan = plan("""
+ from test
+ | keep emp_no, salary, gender
+ | inlinestats m1 = count(salary) where not false
+ """);
+ var limit = as(plan, Limit.class);
+ var ij = as(limit.child(), InlineJoin.class);
+
+ var left = as(ij.left(), EsqlProject.class);
+ assertThat(Expressions.names(left.projections()), contains("emp_no", "salary", "gender"));
+ var leftLimit = as(left.child(), Limit.class);
+ as(leftLimit.child(), EsRelation.class);
+
+ var right = as(ij.right(), Aggregate.class);
+ assertThat(Expressions.names(right.aggregates()), contains("m1"));
+ assertEquals(1, right.aggregates().size());
+ assertTrue(right.aggregates().get(0).children().get(0) instanceof Count);
+ assertEquals("true", ((Count) right.aggregates().get(0).children().get(0)).filter().toString());
+
+ var source = as(right.child(), StubRelation.class);
+ assertThat(Expressions.names(source.output()), contains("emp_no", "salary", "gender"));
+ }
+
+ /**
+ * EsqlProject[[salary{f}#10, count(salary) where false{r}#4]]
+ * \_Eval[[0[LONG] AS count(salary) where false#4]]
+ * \_Limit[1000[INTEGER],false]
+ * \_EsRelation[test][_meta_field{f}#11, emp_no{f}#5, first_name{f}#6, ge..]
+ */
+ public void testReplaceInlinestatsFilteredAggWithEvalCount() {
+ var plan = plan("""
+ from test
+ | keep salary
+ | inlinestats count(salary) where false
+ """);
+ var project = as(plan, EsqlProject.class);
+ assertThat(Expressions.names(project.projections()), contains("salary", "count(salary) where false"));
+
+ var eval = as(project.child(), Eval.class);
+ assertThat(eval.fields().size(), is(1));
+ var alias = as(eval.fields().getFirst(), Alias.class);
+ assertThat(alias.name(), is("count(salary) where false"));
+ assertTrue(alias.child().foldable());
+ assertThat(alias.child().fold(FoldContext.small()), is(0L));
+
+ var limit = as(eval.child(), Limit.class);
+ as(limit.child(), EsRelation.class);
+ }
+
+ /**
+ * EsqlProject[[salary{f}#10, count_distinct(salary 2) 3 where false{r}#4]]
+ * \_Eval[[3[LONG] AS count_distinct(salary 2) 3 where false#4]]
+ * \_Limit[1000[INTEGER],false]
+ * \_EsRelation[test][_meta_field{f}#11, emp_no{f}#5, first_name{f}#6, ge..]
+ */
+ public void testReplaceInlinestatsFilteredAggWithEvalCountDistinctInExpression() {
+ var plan = plan("""
+ from test
+ | keep salary
+ | inlinestats count_distinct(salary + 2) + 3 where false
+ """);
+ var project = as(plan, EsqlProject.class);
+ assertThat(Expressions.names(project.projections()), contains("salary", "count_distinct(salary + 2) + 3 where false"));
+
+ var eval = as(project.child(), Eval.class);
+ assertThat(eval.fields().size(), is(1));
+ var alias = as(eval.fields().getFirst(), Alias.class);
+ assertThat(alias.name(), is("count_distinct(salary + 2) + 3 where false"));
+ assertTrue(alias.child().foldable());
+ assertThat(alias.child().fold(FoldContext.small()), is(3L));
+
+ var limit = as(eval.child(), Limit.class);
+ as(limit.child(), EsRelation.class);
+ }
+
+ /*
+ * Limit[1000[INTEGER],true]
+ * \_InlineJoin[LEFT,[emp_no{f}#17],[emp_no{f}#17],[emp_no{r}#17]]
+ * |_EsqlProject[[emp_no{f}#17, salary{f}#22]]
+ * | \_Limit[1000[INTEGER],false]
+ * | \_EsRelation[test][_meta_field{f}#23, emp_no{f}#17, first_name{f}#18, ..]
+ * \_Project[[max{r}#6, max_a{r}#9, min{r}#12, min_a{r}#15, emp_no{f}#17]]
+ * \_Eval[[null[INTEGER] AS max_a#9, null[INTEGER] AS min_a#15]]
+ * \_Aggregate[[emp_no{f}#17],[MAX(salary{f}#22,true[BOOLEAN]) AS max#6, MIN(salary{f}#22,true[BOOLEAN]) AS min#12, emp_no{f}#17]]
+ * \_StubRelation[[emp_no{f}#17, salary{f}#22]]
+ */
+ public void testReplaceInlinestatsFilteredAggWithEvalSameAggWithAndWithoutFilter() {
+ var plan = plan("""
+ from test
+ | keep emp_no, salary
+ | inlinestats max = max(salary), max_a = max(salary) where null,
+ min = min(salary),
+ min_a = min(salary) where to_string(null) == "abc"
+ by emp_no
+ """);
+ var limit = as(plan, Limit.class);
+ var ij = as(limit.child(), InlineJoin.class);
+
+ var left = as(ij.left(), EsqlProject.class);
+ assertThat(Expressions.names(left.projections()), contains("emp_no", "salary"));
+ var leftLimit = as(left.child(), Limit.class);
+ as(leftLimit.child(), EsRelation.class);
+
+ var right = as(ij.right(), Project.class);
+ assertThat(Expressions.names(right.projections()), contains("max", "max_a", "min", "min_a", "emp_no"));
+
+ var eval = as(right.child(), Eval.class);
+ assertThat(eval.fields().size(), is(2));
+
+ var aliasMaxA = as(eval.fields().get(0), Alias.class);
+ assertThat(Expressions.name(aliasMaxA), containsString("max_a"));
+ assertTrue(aliasMaxA.child().foldable());
+ assertThat(aliasMaxA.child().fold(FoldContext.small()), nullValue());
+ assertThat(aliasMaxA.child().dataType(), is(INTEGER));
+
+ var aliasMinA = as(eval.fields().get(1), Alias.class);
+ assertThat(Expressions.name(aliasMinA), containsString("min_a"));
+ assertTrue(aliasMinA.child().foldable());
+ assertThat(aliasMinA.child().fold(FoldContext.small()), nullValue());
+ assertThat(aliasMinA.child().dataType(), is(INTEGER));
+
+ var aggregate = as(eval.child(), Aggregate.class);
+ assertThat(Expressions.names(aggregate.aggregates()), contains("max", "min", "emp_no"));
+
+ var source = as(aggregate.child(), StubRelation.class);
+ assertThat(Expressions.names(source.output()), contains("emp_no", "salary"));
+ }
+
+ /*
+ * EsqlProject[[emp_no{f}#9, count{r}#5, cc{r}#8]]
+ * \_Eval[[0[LONG] AS count#5, 0[LONG] AS cc#8]]
+ * \_TopN[[Order[emp_no{f}#9,ASC,LAST]],3[INTEGER]]
+ * \_EsRelation[test][_meta_field{f}#15, emp_no{f}#9, first_name{f}#10, g..]
+ */
+ public void testReplaceTwoConsecutiveInlinestats_WithFalseFilters() {
+ var plan = plan("""
+ from test
+ | keep emp_no
+ | sort emp_no
+ | limit 3
+ | inlinestats count = count(*) where false
+ | inlinestats cc = count_distinct(emp_no) where false
+ """);
+
+ var project = as(plan, EsqlProject.class);
+ assertThat(Expressions.names(project.projections()), contains("emp_no", "count", "cc"));
+
+ var eval = as(project.child(), Eval.class);
+ assertThat(eval.fields().size(), is(2));
+
+ var aliasCount = as(eval.fields().get(0), Alias.class);
+ assertThat(Expressions.name(aliasCount), startsWith("count"));
+ assertTrue(aliasCount.child().foldable());
+ assertThat(aliasCount.child().fold(FoldContext.small()), is(0L));
+
+ var aliasCc = as(eval.fields().get(1), Alias.class);
+ assertThat(Expressions.name(aliasCc), startsWith("cc"));
+ assertTrue(aliasCc.child().foldable());
+ assertThat(aliasCc.child().fold(FoldContext.small()), is(0L));
+
+ var topN = as(eval.child(), TopN.class);
+ as(topN.child(), EsRelation.class);
+ }
+}
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/session/FieldNameUtilsTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/session/FieldNameUtilsTests.java
index 5f773a69e8664..916b14c8de9e9 100644
--- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/session/FieldNameUtilsTests.java
+++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/session/FieldNameUtilsTests.java
@@ -34,7 +34,7 @@ public void testBasicFromCommand() {
}
public void testBasicFromCommandWithInlinestats() {
- assumeTrue("INLINESTATS required", EsqlCapabilities.Cap.INLINESTATS_V9.isEnabled());
+ assumeTrue("INLINESTATS required", EsqlCapabilities.Cap.INLINESTATS_V10.isEnabled());
assertFieldNames("from test | inlinestats max(salary) by gender", ALL_FIELDS);
}
@@ -43,7 +43,7 @@ public void testBasicFromCommandWithMetadata() {
}
public void testBasicFromCommandWithMetadata_AndInlinestats() {
- assumeTrue("INLINESTATS required", EsqlCapabilities.Cap.INLINESTATS_V9.isEnabled());
+ assumeTrue("INLINESTATS required", EsqlCapabilities.Cap.INLINESTATS_V10.isEnabled());
assertFieldNames("from test metadata _index, _id, _version | inlinestats max(salary)", ALL_FIELDS);
}
@@ -320,7 +320,7 @@ public void testLimitZero() {
}
public void testLimitZero_WithInlinestats() {
- assumeTrue("INLINESTATS required", EsqlCapabilities.Cap.INLINESTATS_V9.isEnabled());
+ assumeTrue("INLINESTATS required", EsqlCapabilities.Cap.INLINESTATS_V10.isEnabled());
assertFieldNames("""
FROM employees
| INLINESTATS COUNT(*), MAX(salary) BY gender
@@ -335,7 +335,7 @@ public void testDocsDropHeight() {
}
public void testDocsDropHeight_WithInlinestats() {
- assumeTrue("INLINESTATS required", EsqlCapabilities.Cap.INLINESTATS_V9.isEnabled());
+ assumeTrue("INLINESTATS required", EsqlCapabilities.Cap.INLINESTATS_V10.isEnabled());
assertFieldNames("""
FROM employees
| DROP height
@@ -351,7 +351,7 @@ public void testDocsDropHeightWithWildcard() {
}
public void testDocsDropHeightWithWildcard_AndInlinestats() {
- assumeTrue("INLINESTATS required", EsqlCapabilities.Cap.INLINESTATS_V9.isEnabled());
+ assumeTrue("INLINESTATS required", EsqlCapabilities.Cap.INLINESTATS_V10.isEnabled());
assertFieldNames("""
FROM employees
| INLINESTATS MAX(salary) BY gender
@@ -518,7 +518,7 @@ public void testSortWithLimitOne_DropHeight() {
}
public void testSortWithLimitOne_DropHeight_WithInlinestats() {
- assumeTrue("INLINESTATS required", EsqlCapabilities.Cap.INLINESTATS_V9.isEnabled());
+ assumeTrue("INLINESTATS required", EsqlCapabilities.Cap.INLINESTATS_V10.isEnabled());
assertFieldNames("from employees | inlinestats avg(salary) by languages | sort languages | limit 1 | drop height*", ALL_FIELDS);
}
@@ -818,7 +818,7 @@ public void testFilterById() {
}
public void testFilterById_WithInlinestats() {
- assumeTrue("INLINESTATS required", EsqlCapabilities.Cap.INLINESTATS_V9.isEnabled());
+ assumeTrue("INLINESTATS required", EsqlCapabilities.Cap.INLINESTATS_V10.isEnabled());
assertFieldNames("FROM apps metadata _id | INLINESTATS max(rate) | WHERE _id == \"4\"", ALL_FIELDS);
}
@@ -1289,7 +1289,7 @@ public void testProjectDropPattern() {
}
public void testProjectDropPattern_WithInlinestats() {
- assumeTrue("INLINESTATS required", EsqlCapabilities.Cap.INLINESTATS_V9.isEnabled());
+ assumeTrue("INLINESTATS required", EsqlCapabilities.Cap.INLINESTATS_V10.isEnabled());
assertFieldNames("""
from test
| inlinestats max(foo) by bar
@@ -1372,7 +1372,7 @@ public void testCountAllAndOtherStatGrouped() {
}
public void testCountAllAndOtherStatGrouped_WithInlinestats() {
- assumeTrue("INLINESTATS required", EsqlCapabilities.Cap.INLINESTATS_V9.isEnabled());
+ assumeTrue("INLINESTATS required", EsqlCapabilities.Cap.INLINESTATS_V10.isEnabled());
assertFieldNames("""
from test
| inlinestats c = count(*), min = min(emp_no) by languages
@@ -1411,7 +1411,7 @@ public void testCountAllWithEval() {
}
public void testCountAllWithEval_AndInlinestats() {
- assumeTrue("INLINESTATS required", EsqlCapabilities.Cap.INLINESTATS_V9.isEnabled());
+ assumeTrue("INLINESTATS required", EsqlCapabilities.Cap.INLINESTATS_V10.isEnabled());
assertFieldNames("""
from test
| rename languages as l
@@ -1424,7 +1424,7 @@ public void testCountAllWithEval_AndInlinestats() {
}
public void testKeepAfterEval_AndInlinestats() {
- assumeTrue("INLINESTATS required", EsqlCapabilities.Cap.INLINESTATS_V9.isEnabled());
+ assumeTrue("INLINESTATS required", EsqlCapabilities.Cap.INLINESTATS_V10.isEnabled());
assertFieldNames("""
from test
| rename languages as l
@@ -1437,7 +1437,7 @@ public void testKeepAfterEval_AndInlinestats() {
}
public void testKeepBeforeEval_AndInlinestats() {
- assumeTrue("INLINESTATS required", EsqlCapabilities.Cap.INLINESTATS_V9.isEnabled());
+ assumeTrue("INLINESTATS required", EsqlCapabilities.Cap.INLINESTATS_V10.isEnabled());
assertFieldNames("""
from test
| rename languages as l
@@ -1450,7 +1450,7 @@ public void testKeepBeforeEval_AndInlinestats() {
}
public void testStatsBeforeEval_AndInlinestats() {
- assumeTrue("INLINESTATS required", EsqlCapabilities.Cap.INLINESTATS_V9.isEnabled());
+ assumeTrue("INLINESTATS required", EsqlCapabilities.Cap.INLINESTATS_V10.isEnabled());
assertFieldNames("""
from test
| rename languages as l
@@ -1462,7 +1462,7 @@ public void testStatsBeforeEval_AndInlinestats() {
}
public void testStatsBeforeInlinestats() {
- assumeTrue("INLINESTATS required", EsqlCapabilities.Cap.INLINESTATS_V9.isEnabled());
+ assumeTrue("INLINESTATS required", EsqlCapabilities.Cap.INLINESTATS_V10.isEnabled());
assertFieldNames("""
from test
| stats min = min(salary) by languages
@@ -1471,7 +1471,7 @@ public void testStatsBeforeInlinestats() {
}
public void testKeepBeforeInlinestats() {
- assumeTrue("INLINESTATS required", EsqlCapabilities.Cap.INLINESTATS_V9.isEnabled());
+ assumeTrue("INLINESTATS required", EsqlCapabilities.Cap.INLINESTATS_V10.isEnabled());
assertFieldNames("""
from test
| keep languages, salary
@@ -2845,7 +2845,7 @@ public void testForkAfterMvExpand() {
}
public void testForkBeforeInlineStatsIgnore() {
- assumeTrue("INLINESTATS required", EsqlCapabilities.Cap.INLINESTATS_V9.isEnabled());
+ assumeTrue("INLINESTATS required", EsqlCapabilities.Cap.INLINESTATS_V10.isEnabled());
assertTrue("FORK required", EsqlCapabilities.Cap.FORK_V9.isEnabled());
assertFieldNames("""
FROM employees
@@ -2858,7 +2858,7 @@ public void testForkBeforeInlineStatsIgnore() {
}
public void testForkBranchWithInlineStatsIgnore() {
- assumeTrue("INLINESTATS required", EsqlCapabilities.Cap.INLINESTATS_V9.isEnabled());
+ assumeTrue("INLINESTATS required", EsqlCapabilities.Cap.INLINESTATS_V10.isEnabled());
assertTrue("FORK required", EsqlCapabilities.Cap.FORK_V9.isEnabled());
assertFieldNames("""
FROM employees
@@ -2872,7 +2872,7 @@ public void testForkBranchWithInlineStatsIgnore() {
}
public void testForkAfterInlineStatsIgnore() {
- assumeTrue("INLINESTATS required", EsqlCapabilities.Cap.INLINESTATS_V9.isEnabled());
+ assumeTrue("INLINESTATS required", EsqlCapabilities.Cap.INLINESTATS_V10.isEnabled());
assertTrue("FORK required", EsqlCapabilities.Cap.FORK_V9.isEnabled());
assertFieldNames("""
FROM employees