|
@@ -43,6 +43,7 @@ import org.elasticsearch.xpack.esql.core.expression.Alias;
|
|
|
import org.elasticsearch.xpack.esql.core.expression.Expression;
|
|
|
import org.elasticsearch.xpack.esql.core.expression.Expressions;
|
|
|
import org.elasticsearch.xpack.esql.core.expression.FieldAttribute;
|
|
|
+import org.elasticsearch.xpack.esql.core.expression.FoldContext;
|
|
|
import org.elasticsearch.xpack.esql.core.expression.Literal;
|
|
|
import org.elasticsearch.xpack.esql.core.expression.NamedExpression;
|
|
|
import org.elasticsearch.xpack.esql.core.expression.ReferenceAttribute;
|
|
@@ -52,9 +53,11 @@ import org.elasticsearch.xpack.esql.core.type.EsField;
|
|
|
import org.elasticsearch.xpack.esql.core.type.MultiTypeEsField;
|
|
|
import org.elasticsearch.xpack.esql.core.util.Holder;
|
|
|
import org.elasticsearch.xpack.esql.enrich.ResolvedEnrichPolicy;
|
|
|
+import org.elasticsearch.xpack.esql.expression.Order;
|
|
|
import org.elasticsearch.xpack.esql.expression.function.EsqlFunctionRegistry;
|
|
|
import org.elasticsearch.xpack.esql.expression.function.UnsupportedAttribute;
|
|
|
import org.elasticsearch.xpack.esql.expression.function.aggregate.Count;
|
|
|
+import org.elasticsearch.xpack.esql.expression.function.aggregate.Min;
|
|
|
import org.elasticsearch.xpack.esql.expression.function.fulltext.FullTextFunction;
|
|
|
import org.elasticsearch.xpack.esql.expression.function.fulltext.Kql;
|
|
|
import org.elasticsearch.xpack.esql.expression.function.fulltext.Match;
|
|
@@ -131,8 +134,12 @@ import static org.elasticsearch.xpack.esql.analysis.AnalyzerTestUtils.defaultLoo
|
|
|
import static org.elasticsearch.xpack.esql.analysis.AnalyzerTestUtils.indexWithDateDateNanosUnionType;
|
|
|
import static org.elasticsearch.xpack.esql.core.querydsl.query.Query.unscore;
|
|
|
import static org.elasticsearch.xpack.esql.core.type.DataType.DATE_NANOS;
|
|
|
+import static org.elasticsearch.xpack.esql.core.type.DataType.INTEGER;
|
|
|
+import static org.elasticsearch.xpack.esql.core.util.TestUtils.getFieldAttribute;
|
|
|
+import static org.elasticsearch.xpack.esql.plan.physical.AbstractPhysicalPlanSerializationTests.randomEstimatedRowSize;
|
|
|
import static org.elasticsearch.xpack.esql.plan.physical.EsStatsQueryExec.StatsType;
|
|
|
import static org.hamcrest.Matchers.contains;
|
|
|
+import static org.hamcrest.Matchers.containsString;
|
|
|
import static org.hamcrest.Matchers.equalTo;
|
|
|
import static org.hamcrest.Matchers.hasSize;
|
|
|
import static org.hamcrest.Matchers.instanceOf;
|
|
@@ -2056,6 +2063,37 @@ public class LocalPhysicalPlanOptimizerTests extends MapperServiceTestCase {
|
|
|
assertThat(expected.toString(), is(esQuery.query().toString()));
|
|
|
}
|
|
|
|
|
|
+ public void testVerifierOnMissingReferences() throws Exception {
|
|
|
+
|
|
|
+ PhysicalPlan plan = plannerOptimizer.plan("""
|
|
|
+ from test
|
|
|
+ | stats a = min(salary) by emp_no
|
|
|
+ """);
|
|
|
+
|
|
|
+ var limit = as(plan, LimitExec.class);
|
|
|
+ var aggregate = as(limit.child(), AggregateExec.class);
|
|
|
+ var min = as(Alias.unwrap(aggregate.aggregates().get(0)), Min.class);
|
|
|
+ var salary = as(min.field(), NamedExpression.class);
|
|
|
+ assertThat(salary.name(), is("salary"));
|
|
|
+ // emulate a rule that adds a missing attribute
|
|
|
+ FieldAttribute missingAttr = getFieldAttribute("missing attr");
|
|
|
+ List<Order> orders = List.of(new Order(plan.source(), missingAttr, Order.OrderDirection.ASC, Order.NullsPosition.FIRST));
|
|
|
+ TopNExec topNExec = new TopNExec(plan.source(), plan, orders, new Literal(Source.EMPTY, limit, INTEGER), randomEstimatedRowSize());
|
|
|
+
|
|
|
+ // We want to verify that the localOptimize detects the missing attribute.
|
|
|
+ // However, it also throws an error in one of the rules before we get to the verifier.
|
|
|
+ // So we use an implementation of LocalPhysicalPlanOptimizer that does not have any rules.
|
|
|
+ LocalPhysicalOptimizerContext context = new LocalPhysicalOptimizerContext(config, FoldContext.small(), SearchStats.EMPTY);
|
|
|
+ LocalPhysicalPlanOptimizer optimizerWithNoopExecute = new LocalPhysicalPlanOptimizer(context) {
|
|
|
+ @Override
|
|
|
+ protected List<Batch<PhysicalPlan>> batches() {
|
|
|
+ return List.of();
|
|
|
+ }
|
|
|
+ };
|
|
|
+ Exception e = expectThrows(IllegalStateException.class, () -> optimizerWithNoopExecute.localOptimize(topNExec));
|
|
|
+ assertThat(e.getMessage(), containsString(" optimized incorrectly due to missing references [missing attr"));
|
|
|
+ }
|
|
|
+
|
|
|
private boolean isMultiTypeEsField(Expression e) {
|
|
|
return e instanceof FieldAttribute fa && fa.field() instanceof MultiTypeEsField;
|
|
|
}
|