|
23 | 23 | import org.elasticsearch.xpack.esql.core.expression.FieldAttribute; |
24 | 24 | import org.elasticsearch.xpack.esql.core.expression.FoldContext; |
25 | 25 | import org.elasticsearch.xpack.esql.core.expression.Literal; |
| 26 | +import org.elasticsearch.xpack.esql.core.expression.NamedExpression; |
26 | 27 | import org.elasticsearch.xpack.esql.core.expression.ReferenceAttribute; |
27 | 28 | import org.elasticsearch.xpack.esql.core.tree.NodeInfo; |
28 | 29 | import org.elasticsearch.xpack.esql.core.tree.Source; |
29 | 30 | import org.elasticsearch.xpack.esql.core.type.DataType; |
30 | 31 | import org.elasticsearch.xpack.esql.core.type.EsField; |
31 | 32 | import org.elasticsearch.xpack.esql.core.type.InvalidMappedField; |
| 33 | +import org.elasticsearch.xpack.esql.expression.Order; |
32 | 34 | import org.elasticsearch.xpack.esql.expression.function.EsqlFunctionRegistry; |
| 35 | +import org.elasticsearch.xpack.esql.expression.function.aggregate.Min; |
33 | 36 | import org.elasticsearch.xpack.esql.expression.function.scalar.conditional.Case; |
34 | 37 | import org.elasticsearch.xpack.esql.expression.function.scalar.nulls.Coalesce; |
35 | 38 | import org.elasticsearch.xpack.esql.expression.function.scalar.string.StartsWith; |
|
49 | 52 | import org.elasticsearch.xpack.esql.plan.logical.Limit; |
50 | 53 | import org.elasticsearch.xpack.esql.plan.logical.LogicalPlan; |
51 | 54 | import org.elasticsearch.xpack.esql.plan.logical.MvExpand; |
| 55 | +import org.elasticsearch.xpack.esql.plan.logical.OrderBy; |
52 | 56 | import org.elasticsearch.xpack.esql.plan.logical.Project; |
53 | 57 | import org.elasticsearch.xpack.esql.plan.logical.Row; |
54 | 58 | import org.elasticsearch.xpack.esql.plan.logical.UnaryPlan; |
|
64 | 68 | import java.util.Map; |
65 | 69 | import java.util.Set; |
66 | 70 |
|
| 71 | +import static java.util.Arrays.asList; |
67 | 72 | import static java.util.Collections.emptyMap; |
68 | 73 | import static org.elasticsearch.xpack.esql.EsqlTestUtils.L; |
69 | 74 | import static org.elasticsearch.xpack.esql.EsqlTestUtils.ONE; |
|
84 | 89 | import static org.elasticsearch.xpack.esql.EsqlTestUtils.withDefaultLimitWarning; |
85 | 90 | import static org.elasticsearch.xpack.esql.core.tree.Source.EMPTY; |
86 | 91 | import static org.hamcrest.Matchers.contains; |
| 92 | +import static org.hamcrest.Matchers.containsString; |
87 | 93 | import static org.hamcrest.Matchers.equalTo; |
88 | 94 | import static org.hamcrest.Matchers.hasSize; |
89 | 95 | import static org.hamcrest.Matchers.is; |
@@ -774,6 +780,32 @@ public void testGroupingByMissingFields() { |
774 | 780 | as(eval.child(), EsRelation.class); |
775 | 781 | } |
776 | 782 |
|
| 783 | + public void testPlanSanityCheck() throws Exception { |
| 784 | + var plan = localPlan(""" |
| 785 | + from test |
| 786 | + | stats a = min(salary) by emp_no |
| 787 | + """); |
| 788 | + |
| 789 | + var limit = as(plan, Limit.class); |
| 790 | + var aggregate = as(limit.child(), Aggregate.class); |
| 791 | + var min = as(Alias.unwrap(aggregate.aggregates().get(0)), Min.class); |
| 792 | + var salary = as(min.field(), NamedExpression.class); |
| 793 | + assertThat(salary.name(), is("salary")); |
| 794 | + // emulate a rule that adds an invalid field |
| 795 | + var invalidPlan = new OrderBy( |
| 796 | + limit.source(), |
| 797 | + limit, |
| 798 | + asList(new Order(limit.source(), salary, Order.OrderDirection.ASC, Order.NullsPosition.FIRST)) |
| 799 | + ); |
| 800 | + |
| 801 | + var localContext = new LocalLogicalOptimizerContext(EsqlTestUtils.TEST_CFG, FoldContext.small(), TEST_SEARCH_STATS); |
| 802 | + LocalLogicalPlanOptimizer localLogicalPlanOptimizer = new LocalLogicalPlanOptimizer(localContext); |
| 803 | + |
| 804 | + IllegalStateException e = expectThrows(IllegalStateException.class, () -> localLogicalPlanOptimizer.localOptimize(invalidPlan)); |
| 805 | + assertThat(e.getMessage(), containsString("Plan [OrderBy[[Order[salary")); |
| 806 | + assertThat(e.getMessage(), containsString(" optimized incorrectly due to missing references [salary")); |
| 807 | + } |
| 808 | + |
777 | 809 | private IsNotNull isNotNull(Expression field) { |
778 | 810 | return new IsNotNull(EMPTY, field); |
779 | 811 | } |
|
0 commit comments