diff --git a/docs/changelog/127564.yaml b/docs/changelog/127564.yaml new file mode 100644 index 0000000000000..4604763542b57 --- /dev/null +++ b/docs/changelog/127564.yaml @@ -0,0 +1,6 @@ +pr: 127564 +summary: Consider inlinestats when having `field_caps` check for field names +area: ES|QL +type: bug +issues: + - 127236 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 911d02a8e15ce..fa74400d000a7 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 @@ -48,7 +48,7 @@ import static org.elasticsearch.xpack.esql.EsqlTestUtils.classpathResources; import static org.elasticsearch.xpack.esql.action.EsqlCapabilities.Cap.INLINESTATS; import static org.elasticsearch.xpack.esql.action.EsqlCapabilities.Cap.INLINESTATS_V2; -import static org.elasticsearch.xpack.esql.action.EsqlCapabilities.Cap.INLINESTATS_V6; +import static org.elasticsearch.xpack.esql.action.EsqlCapabilities.Cap.INLINESTATS_V7; 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; @@ -126,7 +126,7 @@ protected void shouldSkipTest(String testName) throws IOException { assumeFalse("INLINESTATS not yet supported in CCS", testCase.requiredCapabilities.contains(INLINESTATS.capabilityName())); assumeFalse("INLINESTATS not yet supported in CCS", testCase.requiredCapabilities.contains(INLINESTATS_V2.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_V6.capabilityName())); + assumeFalse("INLINESTATS not yet supported in CCS", testCase.requiredCapabilities.contains(INLINESTATS_V7.capabilityName())); assumeFalse("LOOKUP JOIN not yet supported in CCS", testCase.requiredCapabilities.contains(JOIN_LOOKUP_V12.capabilityName())); // Unmapped fields require a coorect capability response from every cluster, which isn't currently implemented. assumeFalse("UNMAPPED FIELDS not yet supported in CCS", testCase.requiredCapabilities.contains(UNMAPPED_FIELDS.capabilityName())); 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 f523e7ff7ab0a..30ed34d9ec611 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 @@ -2,8 +2,21 @@ // TODO: re-enable the commented tests once the Join functionality stabilizes // +allFieldsReturned +required_capability: inlinestats_v7 + +FROM hosts METADATA _index +| INLINESTATS c = COUNT(*) BY host_group +| SORT c +| LIMIT 1 +; + + card:keyword | description:text | host:keyword | ip0:ip | ip1:ip |_index:keyword | c:long | host_group:text +eth0 |epsilon gw instance|epsilon |[fe80::cae2:65ff:fece:feb9, fe80::cae2:65ff:fece:fec0, fe80::cae2:65ff:fece:fec1]|fe80::cae2:65ff:fece:fec1|hosts |1 |null +; + maxOfInt -required_capability: inlinestats_v6 +required_capability: inlinestats_v7 // tag::max-languages[] FROM employees | KEEP emp_no, languages @@ -25,7 +38,7 @@ emp_no:integer | languages:integer | max_lang:integer ; maxOfIntByKeyword -required_capability: inlinestats_v6 +required_capability: inlinestats_v7 FROM employees | KEEP emp_no, languages, gender @@ -43,7 +56,7 @@ emp_no:integer | languages:integer | max_lang:integer | gender:keyword ; maxOfLongByKeyword -required_capability: inlinestats_v6 +required_capability: inlinestats_v7 FROM employees | KEEP emp_no, avg_worked_seconds, gender @@ -58,7 +71,7 @@ emp_no:integer | avg_worked_seconds:long | max_avg_worked_seconds:long | gender: ; maxOfLong -required_capability: inlinestats_v6 +required_capability: inlinestats_v7 FROM employees | KEEP emp_no, avg_worked_seconds, gender @@ -71,7 +84,7 @@ emp_no:integer | avg_worked_seconds:long | gender:keyword | max_avg_worked_secon ; maxOfLongByCalculatedKeyword -required_capability: inlinestats_v6 +required_capability: inlinestats_v7 // tag::longest-tenured-by-first[] FROM employees @@ -94,7 +107,7 @@ emp_no:integer | avg_worked_seconds:long | last_name:keyword | max_avg_worked_se ; maxOfLongByCalculatedNamedKeyword -required_capability: inlinestats_v6 +required_capability: inlinestats_v7 FROM employees | KEEP emp_no, avg_worked_seconds, last_name @@ -113,7 +126,7 @@ emp_no:integer | avg_worked_seconds:long | last_name:keyword | max_avg_worked_se ; maxOfLongByCalculatedDroppedKeyword -required_capability: inlinestats_v6 +required_capability: inlinestats_v7 FROM employees | INLINESTATS max_avg_worked_seconds = MAX(avg_worked_seconds) BY l = SUBSTRING(last_name, 0, 1) @@ -132,7 +145,7 @@ emp_no:integer | avg_worked_seconds:long | last_name:keyword | max_avg_worked_se ; maxOfLongByEvaledKeyword -required_capability: inlinestats_v6 +required_capability: inlinestats_v7 FROM employees | EVAL l = SUBSTRING(last_name, 0, 1) @@ -152,7 +165,7 @@ emp_no:integer | avg_worked_seconds:long | max_avg_worked_seconds:long | l:keywo ; maxOfLongByInt -required_capability: inlinestats_v6 +required_capability: inlinestats_v7 FROM employees | KEEP emp_no, avg_worked_seconds, languages @@ -170,7 +183,7 @@ emp_no:integer | avg_worked_seconds:long | max_avg_worked_seconds:long | languag ; maxOfLongByIntDouble -required_capability: inlinestats_v6 +required_capability: inlinestats_v7 FROM employees | KEEP emp_no, avg_worked_seconds, languages, height @@ -206,7 +219,7 @@ emp_no:integer | languages:integer | avg_worked_seconds:long | gender:keyword | ; byMultivaluedSimple -required_capability: inlinestats_v6 +required_capability: inlinestats_v7 // tag::mv-group[] FROM airports @@ -224,7 +237,7 @@ abbrev:keyword | type:keyword | scalerank:integer | min_scalerank:integer ; byMultivaluedMvExpand -required_capability: inlinestats_v6 +required_capability: inlinestats_v7 // tag::mv-expand[] FROM airports @@ -244,7 +257,7 @@ GWL |9 |4 |military ; byMvExpand -required_capability: inlinestats_v6 +required_capability: inlinestats_v7 // tag::extreme-airports[] FROM airports @@ -308,7 +321,7 @@ count:long | country:keyword | avg:double ; afterWhere -required_capability: inlinestats_v6 +required_capability: inlinestats_v7 FROM airports | WHERE country != "United States" @@ -346,8 +359,10 @@ abbrev:keyword | scalerank:keyword ACA | four ; -afterEnrich-Ignore +afterEnrich required_capability: join_planning_v1 +required_capability: inlinestats_v7 +required_capability: enrich_load FROM airports | KEEP abbrev, city @@ -360,14 +375,14 @@ FROM airports | LIMIT 3 ; -abbrev:keyword | city:keyword | region:text | "COUNT(*)":long - ALA | Almaty | Жетісу ауданы | 2 - BXJ | Almaty | Жетісу ауданы | 2 - FUK | Fukuoka | 中央区 | 2 +abbrev:keyword | city:keyword | "COUNT(*)":long | region:text + ALA | Almaty | 2 | Жетісу ауданы + BXJ | Almaty | 2 | Жетісу ауданы + FUK | Fukuoka | 2 | 中央区 ; beforeStats -required_capability: inlinestats_v6 +required_capability: inlinestats_v7 FROM airports | EVAL lat = ST_Y(location) @@ -380,7 +395,7 @@ northern:long | southern:long ; beforeKeepSort -required_capability: inlinestats_v6 +required_capability: inlinestats_v7 FROM employees | INLINESTATS max_salary = MAX(salary) by languages @@ -395,7 +410,7 @@ emp_no:integer | languages:integer | max_salary:integer ; beforeKeepWhere -required_capability: inlinestats_v6 +required_capability: inlinestats_v7 FROM employees | INLINESTATS max_salary = MAX(salary) by languages @@ -409,7 +424,7 @@ emp_no:integer | languages:integer | max_salary:integer beforeEnrich required_capability: join_planning_v1 -required_capability: inlinestats_v6 +required_capability: inlinestats_v7 required_capability: enrich_load FROM airports @@ -429,6 +444,7 @@ ACA |Acapulco de Juárez|385 |major |Acapulco de beforeAndAfterEnrich-Ignore required_capability: join_planning_v1 +// does not fail, but it returns null for all values of count_region FROM airports | KEEP abbrev, type, city @@ -440,13 +456,12 @@ FROM airports | LIMIT 3 ; -abbrev:keyword | type:keyword | city:keyword | "COUNT(*)":long | region:text | count_region:long - ABJ | mid | Abidjan | 499 | Abidjan | 1 - ABV | major | Abuja | 385 | Municipal Area Council | 1 - ACA | major | Acapulco de Juárez | 385 | Acapulco de Juárez | 1 +abbrev:keyword | city:keyword |"COUNT(*)":long | type:keyword | count_region:long | region:text +ABJ |Abidjan |499 |mid | 1 |Abidjan +ABV |Abuja |385 |major | 1 |Municipal Area Council +ACA |Acapulco de Juárez|385 |major | 1 |Acapulco de Juárez ; - shadowing-Ignore required_capability: join_planning_v1 @@ -503,7 +518,7 @@ Zürich | Zürich ; byConstant -required_capability: inlinestats_v6 +required_capability: inlinestats_v7 FROM employees | KEEP emp_no, languages @@ -522,7 +537,7 @@ emp_no:integer | languages:integer | max_lang:integer | y:integer ; aggConstant -required_capability: inlinestats_v6 +required_capability: inlinestats_v7 FROM employees | KEEP emp_no @@ -540,7 +555,7 @@ one:integer | emp_no:integer ; percentile -required_capability: inlinestats_v6 +required_capability: inlinestats_v7 FROM employees | KEEP emp_no, salary @@ -559,7 +574,7 @@ emp_no:integer | salary:integer | ninety_fifth_salary:double ; byTwoCalculated -required_capability: inlinestats_v6 +required_capability: inlinestats_v7 FROM airports | WHERE abbrev IS NOT NULL @@ -644,7 +659,7 @@ abbrev:keyword | scalerank:integer | location:geo_point ; groupShadowsField -required_capability: inlinestats_v6 +required_capability: inlinestats_v7 FROM employees | KEEP emp_no, salary, hire_date @@ -663,7 +678,7 @@ emp_no:integer | salary:integer | avg_salary:double | hire_date:datetime ; groupByExpression_And_ExistentField -required_capability: inlinestats_v6 +required_capability: inlinestats_v7 FROM employees | KEEP emp_no, languages, gender | EVAL x = "ABC" @@ -681,7 +696,7 @@ emp_no:integer | languages:integer | x:keyword | max_lang:integer | y:keyword | ; groupByRenamedColumn -required_capability: inlinestats_v6 +required_capability: inlinestats_v7 FROM employees | KEEP emp_no, languages, gender | INLINESTATS max_lang = MAX(languages) BY y = gender @@ -789,7 +804,7 @@ emp_no:integer | languages:integer | gender:keyword|max_lang:integer| y:keyword ; twoAggregatesGroupedBy_AField_And_AnExpression -required_capability: inlinestats_v6 +required_capability: inlinestats_v7 FROM employees | KEEP emp_no, languages, gender, last_name @@ -811,7 +826,7 @@ emp_no:integer |languages:integer|last_name:keyword|max_lang:integer|min_lang:in ; groupByMultipleRenamedColumns_InversedOrder -required_capability: inlinestats_v6 +required_capability: inlinestats_v7 FROM employees | KEEP emp_no, languages, still_hired, gender @@ -829,7 +844,7 @@ emp_no:integer |languages:integer|still_hired:boolean| gender:keyword|max_lang:i ; groupByMultipleRenamedColumns_InversedOrder_ComplexEval -required_capability: inlinestats_v6 +required_capability: inlinestats_v7 FROM employees | KEEP emp_no, languages, still_hired, gender @@ -848,7 +863,7 @@ emp_no:integer |languages:integer|still_hired:boolean| gender:keyword|multilingu ; groupByMultipleRenamedColumns_AndComplexEval -required_capability: inlinestats_v6 +required_capability: inlinestats_v7 FROM employees | KEEP emp_no, languages, still_hired, gender @@ -890,7 +905,7 @@ emp_no:integer |languages:integer|gender:keyword |first_name:keyword | x:keyw ; groupByRenamedExpression -required_capability: inlinestats_v6 +required_capability: inlinestats_v7 FROM employees | KEEP emp_no, languages, gender, last_name @@ -912,7 +927,7 @@ emp_no:integer |languages:integer|last_name:keyword|max_lang:integer|min_lang:in ; doubleFilterOnLeftAndRight_InlineStats_Sides -required_capability: inlinestats_v6 +required_capability: inlinestats_v7 FROM employees | INLINESTATS max_salary = MAX(salary), min_salary = MIN(salary) by languages @@ -933,7 +948,7 @@ emp_no:integer |languages:integer|salary:integer |max_salary:integer|min_salary: ; filterOnInlineStatsAggs -required_capability: inlinestats_v6 +required_capability: inlinestats_v7 FROM employees | INLINESTATS max_salary = MAX(salary), min_salary = MIN(salary) by languages @@ -952,7 +967,7 @@ emp_no:integer |languages:integer|salary:integer |max_salary:integer|min_salary: ; filterOnInlineStatsAggsValues_And_Groupings -required_capability: inlinestats_v6 +required_capability: inlinestats_v7 FROM employees | INLINESTATS max_salary = MAX(salary), min_salary = MIN(salary) by languages @@ -969,3 +984,20 @@ emp_no:integer |languages:integer|salary:integer |max_salary:integer|min_salary: 10011 |5 |31120 |66817 |25324 10066 |5 |31897 |66817 |25324 ; + +// Fails with (in json format only; for format=txt it returns empty result) +// line 1:101: Plan [FieldExtractExec[description{f}#274, host{f}#272, ip0{f}#273, _index..]<[],[]>] optimized incorrectly due to duplicate output attribute ip1{r}#267 +// line 1:101: Plan [TopNExec[[Order[ip1{r}#267,ASC,LAST]],1[INTEGER],null]] optimized incorrectly due to duplicate output attribute ip1{r}#267 +// line 1:44: Plan [HashJoinExec[[host_group{f}#271, card{f}#276],[host_group{f}#271, card{f}#276],[host_group{r}#271, card{r}#276],[ip1{r}#267]]] optimized incorrectly due to duplicate output attribute ip1{r}#267 +inlineStatsOverrideEVALed_FieldWithSameName-Ignore + +FROM hosts METADATA _index +| EVAL x = ip1 +| INLINESTATS ip1 = COUNT(*) BY host_group, card +| SORT ip1 +| LIMIT 1 +; + + description:text | host:keyword | ip0:ip | _index:keyword | x:ip | ip1:long | host_group:text | card:keyword +alpha db server |alpha |127.0.0.1 |hosts |127.0.0.1|1 |DB servers |eth0 +; 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 718b491059632..ae23d4564f5e8 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 @@ -845,7 +845,7 @@ public enum Cap { * Fixes a series of issues with inlinestats which had an incomplete implementation after lookup and inlinestats * were refactored. */ - INLINESTATS_V6(EsqlPlugin.INLINESTATS_FEATURE_FLAG), + INLINESTATS_V7(EsqlPlugin.INLINESTATS_FEATURE_FLAG), /** * Allow mixed numeric types in conditional functions - case, greatest and least diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java index 0ce12610f6939..8524c5b4e9593 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java @@ -90,6 +90,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -563,8 +564,15 @@ private static void resolveFieldNames(LogicalPlan parsed, EnrichResolution enric } static PreAnalysisResult fieldNames(LogicalPlan parsed, Set enrichPolicyMatchFields, PreAnalysisResult result) { - if (false == parsed.anyMatch(plan -> plan instanceof Aggregate || plan instanceof Project)) { + List inlinestats = parsed.collect(InlineStats.class::isInstance); + Set inlinestatsAggs = new HashSet<>(); + for (var i : inlinestats) { + inlinestatsAggs.add(((InlineStats) i).aggregate()); + } + + if (false == parsed.anyMatch(p -> shouldCollectReferencedFields(p, inlinestatsAggs))) { // no explicit columns selection, for example "from employees" + // also, inlinestats only adds columns to the existent output, its Aggregate shouldn't interfere with potentially using "*" return result.withFieldNames(IndexResolver.ALL_FIELDS); } @@ -691,6 +699,13 @@ static PreAnalysisResult fieldNames(LogicalPlan parsed, Set enrichPolicy } } + /** + * Indicates whether the given plan gives an exact list of fields that we need to collect from field_caps. + */ + private static boolean shouldCollectReferencedFields(LogicalPlan plan, Set inlinestatsAggs) { + return plan instanceof Project || (plan instanceof Aggregate agg && inlinestatsAggs.contains(agg) == false); + } + /** * Could a plan "accidentally" override aliases? * Examples are JOIN and ENRICH, that _could_ produce fields with the same 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 e3adf45b61e41..c4c3df349a253 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 @@ -81,7 +81,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_V6.isEnabled()); + assumeTrue("Requires INLINESTATS", EsqlCapabilities.Cap.INLINESTATS_V7.isEnabled()); var plan = plan(""" from test | keep emp_no, languages, gender @@ -124,7 +124,7 @@ public void testGroupingAliasingMoved_To_LeftSideOfJoin() { * {r}#21]] */ public void testGroupingAliasingMoved_To_LeftSideOfJoin_WithExpression() { - assumeTrue("Requires INLINESTATS", EsqlCapabilities.Cap.INLINESTATS_V6.isEnabled()); + assumeTrue("Requires INLINESTATS", EsqlCapabilities.Cap.INLINESTATS_V7.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/session/IndexResolverFieldNamesTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/session/IndexResolverFieldNamesTests.java index dad5dc4b18e84..d3077903fc200 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/session/IndexResolverFieldNamesTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/session/IndexResolverFieldNamesTests.java @@ -29,10 +29,18 @@ public void testBasicFromCommand() { assertFieldNames("from test", ALL_FIELDS); } + public void testBasicFromCommandWithInlinestats() { + assertFieldNames("from test | inlinestats max(salary) by gender", ALL_FIELDS); + } + public void testBasicFromCommandWithMetadata() { assertFieldNames("from test metadata _index, _id, _version", ALL_FIELDS); } + public void testBasicFromCommandWithMetadata_AndInlinestats() { + assertFieldNames("from test metadata _index, _id, _version | inlinestats max(salary)", ALL_FIELDS); + } + public void testBasicEvalAndDrop() { assertFieldNames("from test | eval x = 1 | drop x", ALL_FIELDS); } @@ -294,6 +302,13 @@ public void testLimitZero() { | LIMIT 0""", ALL_FIELDS); } + public void testLimitZero_WithInlinestats() { + assertFieldNames(""" + FROM employees + | INLINESTATS COUNT(*), MAX(salary) BY gender + | LIMIT 0""", ALL_FIELDS); + } + public void testDocsDropHeight() { assertFieldNames(""" FROM employees @@ -301,6 +316,14 @@ public void testDocsDropHeight() { | LIMIT 0""", ALL_FIELDS); } + public void testDocsDropHeight_WithInlinestats() { + assertFieldNames(""" + FROM employees + | DROP height + | INLINESTATS MAX(salary) BY gender + | LIMIT 0""", ALL_FIELDS); + } + public void testDocsDropHeightWithWildcard() { assertFieldNames(""" FROM employees @@ -308,6 +331,14 @@ public void testDocsDropHeightWithWildcard() { | LIMIT 0""", ALL_FIELDS); } + public void testDocsDropHeightWithWildcard_AndInlinestats() { + assertFieldNames(""" + FROM employees + | INLINESTATS MAX(salary) BY gender + | DROP height* + | LIMIT 0""", ALL_FIELDS); + } + public void testDocsEval() { assertFieldNames(""" FROM employees @@ -466,6 +497,10 @@ public void testSortWithLimitOne_DropHeight() { assertFieldNames("from employees | sort languages | limit 1 | drop height*", ALL_FIELDS); } + public void testSortWithLimitOne_DropHeight_WithInlinestats() { + assertFieldNames("from employees | inlinestats avg(salary) by languages | sort languages | limit 1 | drop height*", ALL_FIELDS); + } + public void testDropAllColumns() { assertFieldNames("from employees | keep height | drop height | eval x = 1", Set.of("height", "height.*")); } @@ -758,7 +793,11 @@ public void testSelectAll() { } public void testFilterById() { - assertFieldNames("FROM apps metadata _id| WHERE _id == \"4\"", ALL_FIELDS); + assertFieldNames("FROM apps metadata _id | WHERE _id == \"4\"", ALL_FIELDS); + } + + public void testFilterById_WithInlinestats() { + assertFieldNames("FROM apps metadata _id | INLINESTATS max(rate) | WHERE _id == \"4\"", ALL_FIELDS); } public void testKeepId() { @@ -1227,6 +1266,15 @@ public void testProjectDropPattern() { """, ALL_FIELDS); } + public void testProjectDropPattern_WithInlinestats() { + assertFieldNames(""" + from test + | inlinestats max(foo) by bar + | keep * + | drop *_name + """, ALL_FIELDS); + } + public void testProjectDropNoStarPattern() { assertFieldNames(""" from test @@ -1300,6 +1348,15 @@ public void testCountAllAndOtherStatGrouped() { """, Set.of("emp_no", "emp_no.*", "languages", "languages.*")); } + public void testCountAllAndOtherStatGrouped_WithInlinestats() { + assertFieldNames(""" + from test + | inlinestats c = count(*), min = min(emp_no) by languages + | stats c = count(*), min = min(emp_no) by languages + | sort languages + """, Set.of("emp_no", "emp_no.*", "languages", "languages.*")); + } + public void testCountAllWithImplicitNameOtherStatGrouped() { assertFieldNames(""" from test @@ -1329,6 +1386,69 @@ public void testCountAllWithEval() { """, Set.of("languages", "languages.*", "salary", "salary.*")); } + public void testCountAllWithEval_AndInlinestats() { + assertFieldNames(""" + from test + | rename languages as l + | inlinestats max(salary) by l + | stats min = min(salary) by l + | eval x = min + 1 + | stats ca = count(*), cx = count(x) by l + | sort l + """, Set.of("languages", "languages.*", "salary", "salary.*")); + } + + public void testKeepAfterEval_AndInlinestats() { + assertFieldNames(""" + from test + | rename languages as l + | inlinestats max(salary) by l + | stats min = min(salary) by l + | eval x = min + 1 + | keep x, l + | sort l + """, Set.of("languages", "languages.*", "salary", "salary.*")); + } + + public void testKeepBeforeEval_AndInlinestats() { + assertFieldNames(""" + from test + | rename languages as l + | keep l, salary, emp_no + | inlinestats max(salary) by l + | eval x = `max(salary)` + 1 + | stats min = min(salary) by l + | sort l + """, Set.of("languages", "languages.*", "salary", "salary.*", "emp_no", "emp_no.*")); + } + + public void testStatsBeforeEval_AndInlinestats() { + assertFieldNames(""" + from test + | rename languages as l + | stats min = min(salary) by l + | eval salary = min + 1 + | inlinestats max(salary) by l + | sort l + """, Set.of("languages", "languages.*", "salary", "salary.*")); + } + + public void testStatsBeforeInlinestats() { + assertFieldNames(""" + from test + | stats min = min(salary) by languages + | inlinestats max(min) by languages + """, Set.of("languages", "languages.*", "salary", "salary.*")); + } + + public void testKeepBeforeInlinestats() { + assertFieldNames(""" + from test + | keep languages, salary + | inlinestats max(salary) by languages + """, Set.of("languages", "languages.*", "salary", "salary.*")); + } + public void testCountStar() { assertFieldNames(""" from test