Skip to content

Commit 4d9ec0f

Browse files
[8.x] ESQL: Preserve single aggregate when all attributes are pruned (#126397) (#127126)
* ESQL: Preserve single aggregate when all attributes are pruned (#126397) * Avoid using `EmptyAttribute` * fix compile error --------- Co-authored-by: kanoshiou <[email protected]>
1 parent 4314e09 commit 4d9ec0f

File tree

5 files changed

+67
-2
lines changed

5 files changed

+67
-2
lines changed

docs/changelog/126397.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
pr: 126397
2+
summary: "ESQL: Preserve single aggregate when all attributes are pruned"
3+
area: ES|QL
4+
type: bug
5+
issues:
6+
- 126392

x-pack/plugin/esql/qa/testFixtures/src/main/resources/eval.csv-spec

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -637,3 +637,39 @@ foo:keyword
637637
;
638638

639639

640+
evalAfterAvgUsingSameName
641+
required_capability: remove_empty_attribute_in_merging_output
642+
from employees
643+
| stats avg = avg(salary)
644+
| eval avg = 12
645+
;
646+
647+
avg:integer
648+
12
649+
;
650+
651+
evalAfterStatsUsingSameName
652+
required_capability: remove_empty_attribute_in_merging_output
653+
from employees
654+
| stats count = count(emp_no), median = median(salary), top_salaries = TOP(salary, 3, "desc")
655+
| keep median, top_salaries
656+
| rename top_salaries as median
657+
| eval median = 12
658+
;
659+
660+
median:integer
661+
12
662+
;
663+
664+
evalAfterStatsUsingSameName2
665+
required_capability: remove_empty_attribute_in_merging_output
666+
ROW foo = [10, 11, 12]
667+
| mv_expand foo
668+
| stats sum = sum(foo), max = max(foo)
669+
| rename sum as max
670+
| eval max = 13
671+
;
672+
673+
max:integer
674+
13
675+
;

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,12 @@ public enum Cap {
277277
*/
278278
RENAME_SEQUENTIAL_PROCESSING,
279279

280+
/**
281+
* Support for removing empty attribute in merging output.
282+
* See <a href="https://github.com/elastic/elasticsearch/issues/126392"> EVAL after STATS produces an empty column #126392 </a>
283+
*/
284+
REMOVE_EMPTY_ATTRIBUTE_IN_MERGING_OUTPUT,
285+
280286
/**
281287
* Fix for union-types when some indexes are missing the required field. Done in #111932.
282288
*/

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/PruneColumns.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
import org.elasticsearch.compute.data.BlockUtils;
1212
import org.elasticsearch.index.IndexMode;
1313
import org.elasticsearch.xpack.esql.core.expression.AttributeSet;
14-
import org.elasticsearch.xpack.esql.core.expression.EmptyAttribute;
1514
import org.elasticsearch.xpack.esql.core.expression.Expressions;
1615
import org.elasticsearch.xpack.esql.core.expression.NamedExpression;
1716
import org.elasticsearch.xpack.esql.plan.logical.Aggregate;
@@ -65,7 +64,7 @@ public LogicalPlan apply(LogicalPlan plan) {
6564
if (aggregate.groupings().isEmpty()) {
6665
p = new LocalRelation(
6766
aggregate.source(),
68-
List.of(new EmptyAttribute(aggregate.source())),
67+
List.of(Expressions.attribute(aggregate.aggregates().get(0))),
6968
LocalSupplier.of(
7069
new Block[] { BlockUtils.constantBlock(PlannerUtils.NON_BREAKING_BLOCK_FACTORY, null, 1) }
7170
)

x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/LogicalPlanOptimizerTests.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2725,6 +2725,24 @@ private static List<String> orderNames(TopN topN) {
27252725
return topN.order().stream().map(o -> as(o.child(), NamedExpression.class).name()).toList();
27262726
}
27272727

2728+
/**
2729+
* Expects
2730+
* Eval[[2[INTEGER] AS x]]
2731+
* \_Limit[1000[INTEGER],false]
2732+
* \_LocalRelation[[{e}#9],[ConstantNullBlock[positions=1]]]
2733+
*/
2734+
public void testEvalAfterStats() {
2735+
var plan = optimizedPlan("""
2736+
ROW foo = 1
2737+
| STATS x = max(foo)
2738+
| EVAL x = 2
2739+
""");
2740+
var eval = as(plan, Eval.class);
2741+
var limit = as(eval.child(), Limit.class);
2742+
var localRelation = as(limit.child(), LocalRelation.class);
2743+
assertThat(Expressions.names(eval.output()), contains("x"));
2744+
}
2745+
27282746
public void testCombineLimitWithOrderByThroughFilterAndEval() {
27292747
LogicalPlan plan = optimizedPlan("""
27302748
from test

0 commit comments

Comments
 (0)