diff --git a/docs/reference/query-languages/esql/kibana/definition/inline_cast.json b/docs/reference/query-languages/esql/kibana/definition/inline_cast.json index 7b76b37367f44..e16d6a6ab5991 100644 --- a/docs/reference/query-languages/esql/kibana/definition/inline_cast.json +++ b/docs/reference/query-languages/esql/kibana/definition/inline_cast.json @@ -7,6 +7,7 @@ "date" : "to_datetime", "date_nanos" : "to_date_nanos", "date_period" : "to_dateperiod", + "date_range" : "to_date_range", "datetime" : "to_datetime", "dense_vector" : "to_dense_vector", "double" : "to_double", diff --git a/x-pack/plugin/esql/compute/gen/build.gradle b/x-pack/plugin/esql/compute/gen/build.gradle index c9f2e8c3632bf..0e7a32a628d77 100644 --- a/x-pack/plugin/esql/compute/gen/build.gradle +++ b/x-pack/plugin/esql/compute/gen/build.gradle @@ -2,6 +2,7 @@ apply plugin: 'elasticsearch.build' dependencies { api project(':x-pack:plugin:esql:compute:ann') + implementation project(':libs:core') api 'com.squareup:javapoet:1.13.0' } diff --git a/x-pack/plugin/esql/compute/gen/src/main/java/module-info.java b/x-pack/plugin/esql/compute/gen/src/main/java/module-info.java index 3e4dbac0d3c96..468bab3df1791 100644 --- a/x-pack/plugin/esql/compute/gen/src/main/java/module-info.java +++ b/x-pack/plugin/esql/compute/gen/src/main/java/module-info.java @@ -13,6 +13,7 @@ requires com.squareup.javapoet; requires org.elasticsearch.compute.ann; requires java.compiler; + requires org.elasticsearch.base; exports org.elasticsearch.compute.gen; exports org.elasticsearch.compute.gen.argument; diff --git a/x-pack/plugin/esql/compute/gen/src/main/java/org/elasticsearch/compute/gen/MarkerAnnotationProcessor.java b/x-pack/plugin/esql/compute/gen/src/main/java/org/elasticsearch/compute/gen/MarkerAnnotationProcessor.java new file mode 100644 index 0000000000000..181ad5e5be5da --- /dev/null +++ b/x-pack/plugin/esql/compute/gen/src/main/java/org/elasticsearch/compute/gen/MarkerAnnotationProcessor.java @@ -0,0 +1,67 @@ +/* + * 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.compute.gen; + +import org.elasticsearch.core.UpdateForV10; + +import java.util.Set; + +import javax.annotation.processing.Completion; +import javax.annotation.processing.ProcessingEnvironment; +import javax.annotation.processing.Processor; +import javax.annotation.processing.RoundEnvironment; +import javax.lang.model.SourceVersion; +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; + +/** + * A no-op annotation processor that claims marker annotations like {@code @UpdateForV10}. + *

+ * These annotations are documentation-only markers (with {@code @Retention(SOURCE)}) used to + * track code that needs cleanup in future versions. Since the ESQL module uses annotation + * processors for code generation, the compiler warns about unclaimed annotations. This + * processor claims them to suppress those warnings. + */ +public class MarkerAnnotationProcessor implements Processor { + + @Override + public Set getSupportedOptions() { + return Set.of(); + } + + @Override + public Set getSupportedAnnotationTypes() { + // Marker annotations that are documentation-only and don't require processing. + return Set.of(UpdateForV10.class.getCanonicalName()); + } + + @Override + public SourceVersion getSupportedSourceVersion() { + return SourceVersion.RELEASE_21; + } + + @Override + public void init(ProcessingEnvironment processingEnvironment) {} + + @Override + public Iterable getCompletions( + Element element, + AnnotationMirror annotationMirror, + ExecutableElement executableElement, + String s + ) { + return Set.of(); + } + + @Override + public boolean process(Set annotations, RoundEnvironment roundEnvironment) { + return true; + } +} diff --git a/x-pack/plugin/esql/compute/gen/src/main/resources/META-INF/services/javax.annotation.processing.Processor b/x-pack/plugin/esql/compute/gen/src/main/resources/META-INF/services/javax.annotation.processing.Processor index 51700a418a02b..769712450ff51 100644 --- a/x-pack/plugin/esql/compute/gen/src/main/resources/META-INF/services/javax.annotation.processing.Processor +++ b/x-pack/plugin/esql/compute/gen/src/main/resources/META-INF/services/javax.annotation.processing.Processor @@ -1,3 +1,4 @@ org.elasticsearch.compute.gen.AggregatorProcessor org.elasticsearch.compute.gen.ConsumeProcessor org.elasticsearch.compute.gen.EvaluatorProcessor +org.elasticsearch.compute.gen.MarkerAnnotationProcessor diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/analysis/Analyzer.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/analysis/Analyzer.java index 412d80593c215..2b90e8597c9c2 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/analysis/Analyzer.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/analysis/Analyzer.java @@ -143,7 +143,6 @@ import org.elasticsearch.xpack.esql.plan.logical.join.JoinType; import org.elasticsearch.xpack.esql.plan.logical.join.JoinTypes; import org.elasticsearch.xpack.esql.plan.logical.join.LookupJoin; -import org.elasticsearch.xpack.esql.plan.logical.local.EsqlProject; import org.elasticsearch.xpack.esql.plan.logical.local.LocalRelation; import org.elasticsearch.xpack.esql.plan.logical.local.LocalSupplier; import org.elasticsearch.xpack.esql.plan.logical.promql.PromqlCommand; @@ -908,7 +907,7 @@ private LogicalPlan resolveFork(Fork fork, AnalyzerContext context) { } List subPlanColumns = logicalPlan.output().stream().map(Attribute::name).toList(); - // We need to add an explicit EsqlProject to align the outputs. + // We need to add an explicit Project to align the outputs. if (logicalPlan instanceof Project == false || subPlanColumns.equals(forkColumns) == false) { changed = true; List newOutput = new ArrayList<>(); @@ -1264,7 +1263,7 @@ private LogicalPlan resolveKeep(Project p, List childOutput) { resolvedProjections = new ArrayList<>(priorities.keySet()); } - return new EsqlProject(p.source(), p.child(), resolvedProjections); + return new Project(p.source(), p.child(), resolvedProjections); } private LogicalPlan resolveDrop(Drop drop, List childOutput) { @@ -1294,13 +1293,13 @@ private LogicalPlan resolveDrop(Drop drop, List childOutput) { }); } - return new EsqlProject(drop.source(), drop.child(), resolvedProjections); + return new Project(drop.source(), drop.child(), resolvedProjections); } private LogicalPlan resolveRename(Rename rename, List childrenOutput) { List projections = projectionsForRename(rename, childrenOutput, log); - return new EsqlProject(rename.source(), rename.child(), projections); + return new Project(rename.source(), rename.child(), projections); } /** @@ -2591,12 +2590,12 @@ private static Map> collectConvertFunctions * Push down the conversion functions into the child plan by adding an Eval with the new aliases on top of the child plan. */ private static LogicalPlan maybePushDownConvertFunctionsToChild(LogicalPlan child, List aliases, List output) { - // Fork/UnionAll adds an EsqlProject on top of each child plan during resolveFork, check this pattern before pushing down + // Fork/UnionAll adds an Project on top of each child plan during resolveFork, check this pattern before pushing down // If the pattern doesn't match, something unexpected happened, just return the child as is - if (aliases.isEmpty() == false && child instanceof EsqlProject esqlProject) { - LogicalPlan childOfProject = esqlProject.child(); + if (aliases.isEmpty() == false && child instanceof Project project) { + LogicalPlan childOfProject = project.child(); Eval eval = new Eval(childOfProject.source(), childOfProject, aliases); - return new EsqlProject(esqlProject.source(), eval, output); + return new Project(project.source(), eval, output); } return child; } @@ -2736,7 +2735,7 @@ private static LogicalPlan implicitCastingUnionAllOutput( outputChanged = true; } } - // create a new eval for the casting expressions, and push it down under the EsqlProject + // create a new eval for the casting expressions, and push it down under the Project newChildren.add(maybePushDownConvertFunctionsToChild(child, newAliases, newChildOutput)); } diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/analysis/Verifier.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/analysis/Verifier.java index 2816b3fe89cc3..81c4c46ee878c 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/analysis/Verifier.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/analysis/Verifier.java @@ -114,6 +114,7 @@ Collection verify(LogicalPlan plan, BitSet partialMetrics) { checkOperationsOnUnsignedLong(p, failures); checkBinaryComparison(p, failures); + checkUnsupportedAttributeRenaming(p, failures); checkInsist(p, failures); checkLimitBeforeInlineStats(p, failures); }); @@ -152,14 +153,10 @@ else if (p.resolved()) { } e.forEachUp(ae -> { - // Special handling for Project and unsupported/union types: disallow renaming them but pass them through otherwise. - if (p instanceof Project || p instanceof Insist) { - if (ae instanceof Alias as && as.child() instanceof UnsupportedAttribute ua) { - failures.add(fail(ae, ua.unresolvedMessage())); - } - if (ae instanceof UnsupportedAttribute) { - return; - } + // UnsupportedAttribute can pass through Project/Insist unchanged. + // Renaming is checked separately in #checkUnsupportedAttributeRenaming. + if ((p instanceof Project || p instanceof Insist) && ae instanceof UnsupportedAttribute) { + return; } // Do not fail multiple times in case the children are already unresolved. @@ -275,6 +272,22 @@ private static void checkInsist(LogicalPlan p, Failures failures) { } } + /** + * Check that UnsupportedAttribute is not renamed via Alias in Project or Insist. + * UnsupportedAttribute can pass through these plans unchanged, but renaming is not allowed. + * This check runs unconditionally (not gated by {@link LogicalPlan#resolved()}) because + * {@link Project#expressionsResolved()} treats UnsupportedAttribute as resolved to allow pass-through. + */ + private static void checkUnsupportedAttributeRenaming(LogicalPlan p, Failures failures) { + if (p instanceof Project || p instanceof Insist) { + p.forEachExpression(Alias.class, alias -> { + if (alias.child() instanceof UnsupportedAttribute ua) { + failures.add(fail(alias, ua.unresolvedMessage())); + } + }); + } + } + /* * This is a rudimentary check to prevent INLINE STATS after LIMIT. A LIMIT command can be added by other commands by default, * the best example being FORK. A more robust solution would be to track the commands that add LIMIT and prevent them from doing so diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/PushDownFilterAndLimitIntoUnionAll.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/PushDownFilterAndLimitIntoUnionAll.java index b598e283cc1d6..76e329531cc15 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/PushDownFilterAndLimitIntoUnionAll.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/PushDownFilterAndLimitIntoUnionAll.java @@ -40,23 +40,23 @@ * to {@code Limit} optimization can be applied. * * This rule applies for certain patterns of {@code UnionAll} branches. The branches of a {@code UnionAll}/{@code Fork} plan has a similar - * pattern, as {@code Fork} adds {@code EsqlProject}, an optional {@code Eval} and {@code Limit} on top of its actual children. In case + * pattern, as {@code Fork} adds {@code Project}, an optional {@code Eval} and {@code Limit} on top of its actual children. In case * there is mismatched data types on the same field across different {@code UnionAll} branches, a {@code ConvertFunction} could also be * added in the optional {@code Eval}. * * If the patterns of the {@code UnionAll} branches do not match the following expected patterns, the rule is not applied. * - * EsqlProject + * Project * Eval (optional) - added when the output of each UnionAll branch are not exactly the same * Limit * EsRelation * or - * EsqlProject + * Project * Eval (optional) * Limit * Subquery * or - * Limit - CombineProjections may remove the EsqlProject on top of the limit + * Limit - CombineProjections may remove the Project on top of the limit * Subquery */ public final class PushDownFilterAndLimitIntoUnionAll extends Rule { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/local/PushExpressionsToFieldLoad.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/local/PushExpressionsToFieldLoad.java index f02e1d733447e..e538b9ded443a 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/local/PushExpressionsToFieldLoad.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/local/PushExpressionsToFieldLoad.java @@ -26,7 +26,6 @@ import org.elasticsearch.xpack.esql.plan.logical.Project; import org.elasticsearch.xpack.esql.plan.logical.Row; import org.elasticsearch.xpack.esql.plan.logical.join.StubRelation; -import org.elasticsearch.xpack.esql.plan.logical.local.EsqlProject; import org.elasticsearch.xpack.esql.rule.ParameterizedRule; import java.util.ArrayList; @@ -203,7 +202,7 @@ private LogicalPlan transformPotentialInvocation(LogicalPlan plan) { return plan; } // Found a new pushable attribute, discard it *after* use so we don't modify the output. - return new EsqlProject(Source.EMPTY, transformedPlan, transformedPlan.output()); + return new Project(Source.EMPTY, transformedPlan, transformedPlan.output()); } private Expression transformExpression(LogicalPlan nodeWithExpression, Expression e, BlockLoaderExpression ble) { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/PlanWritables.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/PlanWritables.java index 52da0691d336e..765bf177f2250 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/PlanWritables.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/PlanWritables.java @@ -31,7 +31,6 @@ import org.elasticsearch.xpack.esql.plan.logical.join.Join; import org.elasticsearch.xpack.esql.plan.logical.local.CopyingLocalSupplier; import org.elasticsearch.xpack.esql.plan.logical.local.EmptyLocalSupplier; -import org.elasticsearch.xpack.esql.plan.logical.local.EsqlProject; import org.elasticsearch.xpack.esql.plan.logical.local.ImmediateLocalSupplier; import org.elasticsearch.xpack.esql.plan.logical.local.LocalRelation; import org.elasticsearch.xpack.esql.plan.physical.AggregateExec; @@ -79,7 +78,6 @@ public static List logical() { Dissect.ENTRY, Enrich.ENTRY, EsRelation.ENTRY, - EsqlProject.ENTRY, Eval.ENTRY, Filter.ENTRY, Grok.ENTRY, @@ -92,6 +90,7 @@ public static List logical() { MvExpand.ENTRY, OrderBy.ENTRY, Project.ENTRY, + Project.V9_ENTRY, // Backward compatibility for reading old "EsqlProject" type Rerank.ENTRY, Sample.ENTRY, Subquery.ENTRY, diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Insist.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Insist.java index 63ca4e1099a5f..a1a8aeecd40bf 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Insist.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Insist.java @@ -46,7 +46,7 @@ public Insist replaceChild(LogicalPlan newChild) { @Override public boolean expressionsResolved() { - // Like EsqlProject, we allow unsupported attributes to flow through the engine. + // Like Project, we allow unsupported attributes to flow through the engine. return insistedAttributes().stream().allMatch(a -> a.resolved() || a instanceof UnsupportedAttribute); } diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Project.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Project.java index 2a51d72c4b17b..fef3f84c0faaf 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Project.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Project.java @@ -9,7 +9,7 @@ import org.elasticsearch.common.io.stream.NamedWriteableRegistry; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; -import org.elasticsearch.xpack.esql.core.capabilities.Resolvables; +import org.elasticsearch.core.UpdateForV10; import org.elasticsearch.xpack.esql.core.expression.Alias; import org.elasticsearch.xpack.esql.core.expression.Attribute; import org.elasticsearch.xpack.esql.core.expression.Expressions; @@ -18,6 +18,7 @@ import org.elasticsearch.xpack.esql.core.tree.NodeInfo; import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Functions; +import org.elasticsearch.xpack.esql.expression.function.UnsupportedAttribute; import org.elasticsearch.xpack.esql.io.stream.PlanStreamInput; import java.io.IOException; @@ -30,11 +31,42 @@ public class Project extends UnaryPlan implements Streaming, SortAgnostic, SortPreserving { public static final NamedWriteableRegistry.Entry ENTRY = new NamedWriteableRegistry.Entry(LogicalPlan.class, "Project", Project::new); + /** + * Backward compatibility entry + name for reading the consolidated `EsqlProject` plans from pre-9.4.0 nodes. + */ + private static final String LEGACY_PROJECT_NAME = "EsqlProject"; + + @UpdateForV10(owner = UpdateForV10.Owner.SEARCH_ANALYTICS) + public static final NamedWriteableRegistry.Entry V9_ENTRY = new NamedWriteableRegistry.Entry( + LogicalPlan.class, + LEGACY_PROJECT_NAME, + Project::readLegacyEsqlProject + ); + + private static Project readLegacyEsqlProject(StreamInput in) throws IOException { + return new Project( + Source.readFrom((PlanStreamInput) in), + in.readNamedWriteable(LogicalPlan.class), + in.readNamedWriteableCollectionAsList(NamedExpression.class), + V9_ENTRY.name + ); + } + private final List projections; + private final String writeableName; public Project(Source source, LogicalPlan child, List projections) { + this(source, child, projections, ENTRY.name); + } + + /** + * Constructor that allows specifying a custom writeable name for backward compatibility. + * Used when deserializing legacy "EsqlProject" plans from older cluster versions. + */ + private Project(Source source, LogicalPlan child, List projections, String writeableName) { super(source, child); this.projections = projections; + this.writeableName = writeableName; assert validateProjections(projections); } @@ -55,7 +87,8 @@ private Project(StreamInput in) throws IOException { this( Source.readFrom((PlanStreamInput) in), in.readNamedWriteable(LogicalPlan.class), - in.readNamedWriteableCollectionAsList(NamedExpression.class) + in.readNamedWriteableCollectionAsList(NamedExpression.class), + ENTRY.name ); } @@ -68,7 +101,7 @@ public void writeTo(StreamOutput out) throws IOException { @Override public String getWriteableName() { - return ENTRY.name; + return writeableName; } @Override @@ -96,7 +129,13 @@ public boolean resolved() { @Override public boolean expressionsResolved() { - return Resolvables.resolved(projections); + for (NamedExpression projection : projections) { + // don't call dataType() - it will fail on UnresolvedAttribute + if (projection.resolved() == false && projection instanceof UnsupportedAttribute == false) { + return false; + } + } + return true; } @Override diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/local/EsqlProject.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/local/EsqlProject.java deleted file mode 100644 index 5fb36cf1ebdb1..0000000000000 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/local/EsqlProject.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * 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.plan.logical.local; - -import org.elasticsearch.common.io.stream.NamedWriteableRegistry; -import org.elasticsearch.common.io.stream.StreamInput; -import org.elasticsearch.common.io.stream.StreamOutput; -import org.elasticsearch.xpack.esql.core.expression.NamedExpression; -import org.elasticsearch.xpack.esql.core.tree.NodeInfo; -import org.elasticsearch.xpack.esql.core.tree.Source; -import org.elasticsearch.xpack.esql.expression.function.UnsupportedAttribute; -import org.elasticsearch.xpack.esql.io.stream.PlanStreamInput; -import org.elasticsearch.xpack.esql.plan.logical.LogicalPlan; -import org.elasticsearch.xpack.esql.plan.logical.Project; - -import java.io.IOException; -import java.util.List; - -/** - * A projection when first parsed, i.e. obtained from {@code KEEP, DROP, RENAME}. After the analysis step, we use {@link Project}. - */ -// TODO: Consolidate with Project. We don't need the pre-/post-analysis distinction for other logical plans. -// https://github.com/elastic/elasticsearch/issues/109195 -public class EsqlProject extends Project { - public static final NamedWriteableRegistry.Entry ENTRY = new NamedWriteableRegistry.Entry( - LogicalPlan.class, - "EsqlProject", - EsqlProject::new - ); - - public EsqlProject(Source source, LogicalPlan child, List projections) { - super(source, child, projections); - } - - public EsqlProject(StreamInput in) throws IOException { - this( - Source.readFrom((PlanStreamInput) in), - in.readNamedWriteable(LogicalPlan.class), - in.readNamedWriteableCollectionAsList(NamedExpression.class) - ); - } - - @Override - public void writeTo(StreamOutput out) throws IOException { - Source.EMPTY.writeTo(out); - out.writeNamedWriteable(child()); - out.writeNamedWriteableCollection(projections()); - } - - @Override - public String getWriteableName() { - return ENTRY.name; - } - - @Override - protected NodeInfo info() { - return NodeInfo.create(this, EsqlProject::new, child(), projections()); - } - - @Override - public EsqlProject replaceChild(LogicalPlan newChild) { - return new EsqlProject(source(), newChild, projections()); - } - - @Override - public boolean expressionsResolved() { - for (NamedExpression projection : projections()) { - // don't call dataType() - it will fail on UnresolvedAttribute - if (projection.resolved() == false && projection instanceof UnsupportedAttribute == false) { - return false; - } - } - return true; - } - - @Override - public Project withProjections(List projections) { - return new EsqlProject(source(), child(), projections); - } -} diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/telemetry/FeatureMetric.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/telemetry/FeatureMetric.java index 13537a977ee31..77ff2ab9d4626 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/telemetry/FeatureMetric.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/telemetry/FeatureMetric.java @@ -39,7 +39,6 @@ import org.elasticsearch.xpack.esql.plan.logical.inference.Completion; import org.elasticsearch.xpack.esql.plan.logical.inference.Rerank; import org.elasticsearch.xpack.esql.plan.logical.join.LookupJoin; -import org.elasticsearch.xpack.esql.plan.logical.local.EsqlProject; import org.elasticsearch.xpack.esql.plan.logical.promql.PromqlCommand; import org.elasticsearch.xpack.esql.plan.logical.show.ShowInfo; @@ -86,7 +85,6 @@ public enum FeatureMetric { */ private static final List> excluded = List.of( UnresolvedRelation.class, - EsqlProject.class, Project.class, Limit.class, // LIMIT is managed in another way, see above FuseScoreEval.class, diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/AnalyzerTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/AnalyzerTests.java index 00f3c21689803..862bf4aef2386 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/AnalyzerTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/AnalyzerTests.java @@ -111,7 +111,6 @@ import org.elasticsearch.xpack.esql.plan.logical.inference.Completion; import org.elasticsearch.xpack.esql.plan.logical.inference.Rerank; import org.elasticsearch.xpack.esql.plan.logical.join.LookupJoin; -import org.elasticsearch.xpack.esql.plan.logical.local.EsqlProject; import org.elasticsearch.xpack.esql.session.Configuration; import org.elasticsearch.xpack.esql.session.IndexResolver; @@ -1548,7 +1547,7 @@ public void testEmptyEsRelationOnConstantEvalAndKeep() throws IOException { var limit = as(plan, Limit.class); limit = as(limit.child(), Limit.class); assertThat(as(limit.limit(), Literal.class).value(), equalTo(2)); - var project = as(limit.child(), EsqlProject.class); + var project = as(limit.child(), Project.class); var eval = as(project.child(), Eval.class); assertEmptyEsRelation(eval.child()); } @@ -2184,7 +2183,7 @@ public void testLookup() { matchesList().item(startsWith("int{f}")).item(startsWith("name{f}")) ); - var project = as(lookup.child(), EsqlProject.class); + var project = as(lookup.child(), Project.class); assertThat(project.projections().stream().map(Object::toString).toList(), hasItem(matchesRegex("languages\\{f}#\\d+ AS int#\\d+"))); var esRelation = as(project.child(), EsRelation.class); @@ -2644,8 +2643,8 @@ public void testConditionalFunctionsWithMixedNumericTypes() { private void validateConditionalFunctions(LogicalPlan plan) { var limit = as(plan, Limit.class); - var esqlProject = as(limit.child(), EsqlProject.class); - List projections = esqlProject.projections(); + var project = as(limit.child(), Project.class); + List projections = project.projections(); var projection = as(projections.get(0), ReferenceAttribute.class); assertEquals(projection.name(), "x"); assertEquals(projection.dataType(), DataType.DOUBLE); @@ -3406,7 +3405,7 @@ public void testBasicFork() { // fork branch 1 limit = as(subPlans.get(0), Limit.class); assertThat(as(limit.limit(), Literal.class).value(), equalTo(DEFAULT_LIMIT)); - EsqlProject project = as(limit.child(), EsqlProject.class); + Project project = as(limit.child(), Project.class); List projectColumns = project.expressions().stream().map(exp -> as(exp, Attribute.class).name()).toList(); assertThat(projectColumns, equalTo(expectedOutput)); Eval eval = as(project.child(), Eval.class); @@ -3416,14 +3415,14 @@ public void testBasicFork() { filter = as(filter.child(), Filter.class); assertThat(as(filter.condition(), Equals.class).right(), equalTo(string("Chris"))); - project = as(filter.child(), EsqlProject.class); + project = as(filter.child(), Project.class); var esRelation = as(project.child(), EsRelation.class); assertThat(esRelation.indexPattern(), equalTo("test")); // fork branch 2 limit = as(subPlans.get(1), Limit.class); assertThat(as(limit.limit(), Literal.class).value(), equalTo(DEFAULT_LIMIT)); - project = as(limit.child(), EsqlProject.class); + project = as(limit.child(), Project.class); projectColumns = project.expressions().stream().map(exp -> as(exp, Attribute.class).name()).toList(); assertThat(projectColumns, equalTo(expectedOutput)); eval = as(project.child(), Eval.class); @@ -3433,14 +3432,14 @@ public void testBasicFork() { filter = as(filter.child(), Filter.class); assertThat(as(filter.condition(), Equals.class).right(), equalTo(string("Chris"))); - project = as(filter.child(), EsqlProject.class); + project = as(filter.child(), Project.class); esRelation = as(project.child(), EsRelation.class); assertThat(esRelation.indexPattern(), equalTo("test")); // fork branch 3 limit = as(subPlans.get(2), Limit.class); assertThat(as(limit.limit(), Literal.class).value(), equalTo(MAX_LIMIT)); - project = as(limit.child(), EsqlProject.class); + project = as(limit.child(), Project.class); projectColumns = project.expressions().stream().map(exp -> as(exp, Attribute.class).name()).toList(); assertThat(projectColumns, equalTo(expectedOutput)); eval = as(project.child(), Eval.class); @@ -3452,14 +3451,14 @@ public void testBasicFork() { assertThat(as(filter.condition(), GreaterThan.class).right(), equalTo(literal(3))); filter = as(filter.child(), Filter.class); assertThat(as(filter.condition(), Equals.class).right(), equalTo(string("Chris"))); - project = as(filter.child(), EsqlProject.class); + project = as(filter.child(), Project.class); esRelation = as(project.child(), EsRelation.class); assertThat(esRelation.indexPattern(), equalTo("test")); // fork branch 4 limit = as(subPlans.get(3), Limit.class); assertThat(as(limit.limit(), Literal.class).value(), equalTo(DEFAULT_LIMIT)); - project = as(limit.child(), EsqlProject.class); + project = as(limit.child(), Project.class); projectColumns = project.expressions().stream().map(exp -> as(exp, Attribute.class).name()).toList(); assertThat(projectColumns, equalTo(expectedOutput)); eval = as(project.child(), Eval.class); @@ -3467,14 +3466,14 @@ public void testBasicFork() { orderBy = as(eval.child(), OrderBy.class); filter = as(orderBy.child(), Filter.class); assertThat(as(filter.condition(), Equals.class).right(), equalTo(string("Chris"))); - project = as(filter.child(), EsqlProject.class); + project = as(filter.child(), Project.class); esRelation = as(project.child(), EsRelation.class); assertThat(esRelation.indexPattern(), equalTo("test")); // fork branch 5 limit = as(subPlans.get(4), Limit.class); assertThat(as(limit.limit(), Literal.class).value(), equalTo(MAX_LIMIT)); - project = as(limit.child(), EsqlProject.class); + project = as(limit.child(), Project.class); projectColumns = project.expressions().stream().map(exp -> as(exp, Attribute.class).name()).toList(); assertThat(projectColumns, equalTo(expectedOutput)); eval = as(project.child(), Eval.class); @@ -3483,7 +3482,7 @@ public void testBasicFork() { assertThat(as(limit.limit(), Literal.class).value(), equalTo(9)); filter = as(limit.child(), Filter.class); assertThat(as(filter.condition(), Equals.class).right(), equalTo(string("Chris"))); - project = as(filter.child(), EsqlProject.class); + project = as(filter.child(), Project.class); esRelation = as(project.child(), EsRelation.class); assertThat(esRelation.indexPattern(), equalTo("test")); } @@ -3509,7 +3508,7 @@ public void testForkBranchesWithDifferentSchemas() { // fork branch 1 limit = as(subPlans.get(0), Limit.class); assertThat(as(limit.limit(), Literal.class).value(), equalTo(MAX_LIMIT)); - EsqlProject project = as(limit.child(), EsqlProject.class); + Project project = as(limit.child(), Project.class); List projectColumns = project.expressions().stream().map(exp -> as(exp, Attribute.class).name()).toList(); assertThat(projectColumns, equalTo(expectedOutput)); @@ -3531,7 +3530,7 @@ public void testForkBranchesWithDifferentSchemas() { Filter filter = as(orderBy.child(), Filter.class); assertThat(as(filter.condition(), GreaterThan.class).right(), equalTo(literal(3))); - project = as(filter.child(), EsqlProject.class); + project = as(filter.child(), Project.class); filter = as(project.child(), Filter.class); assertThat(as(filter.condition(), Equals.class).right(), equalTo(string("Chris"))); var esRelation = as(filter.child(), EsRelation.class); @@ -3540,7 +3539,7 @@ public void testForkBranchesWithDifferentSchemas() { // fork branch 2 limit = as(subPlans.get(1), Limit.class); assertThat(as(limit.limit(), Literal.class).value(), equalTo(DEFAULT_LIMIT)); - project = as(limit.child(), EsqlProject.class); + project = as(limit.child(), Project.class); projectColumns = project.expressions().stream().map(exp -> as(exp, Attribute.class).name()).toList(); assertThat(projectColumns, equalTo(expectedOutput)); eval = as(project.child(), Eval.class); @@ -3561,7 +3560,7 @@ public void testForkBranchesWithDifferentSchemas() { filter = as(eval.child(), Filter.class); assertThat(as(filter.condition(), GreaterThan.class).right(), equalTo(literal(2))); - project = as(filter.child(), EsqlProject.class); + project = as(filter.child(), Project.class); filter = as(project.child(), Filter.class); assertThat(as(filter.condition(), Equals.class).right(), equalTo(string("Chris"))); esRelation = as(filter.child(), EsRelation.class); @@ -3570,7 +3569,7 @@ public void testForkBranchesWithDifferentSchemas() { // fork branch 3 limit = as(subPlans.get(2), Limit.class); assertThat(as(limit.limit(), Literal.class).value(), equalTo(DEFAULT_LIMIT)); - project = as(limit.child(), EsqlProject.class); + project = as(limit.child(), Project.class); projectColumns = project.expressions().stream().map(exp -> as(exp, Attribute.class).name()).toList(); assertThat(projectColumns, equalTo(expectedOutput)); eval = as(project.child(), Eval.class); @@ -3606,7 +3605,7 @@ public void testForkBranchesWithDifferentSchemas() { assertThat(dissect.parser().pattern(), equalTo("%{d} %{e} %{f}")); assertThat(as(dissect.input(), FieldAttribute.class).name(), equalTo("first_name")); - project = as(dissect.child(), EsqlProject.class); + project = as(dissect.child(), Project.class); filter = as(project.child(), Filter.class); assertThat(as(filter.condition(), Equals.class).right(), equalTo(string("Chris"))); esRelation = as(filter.child(), EsRelation.class); @@ -3988,8 +3987,8 @@ public void testResolveRerankFields() { Limit limit = as(plan, Limit.class); // Implicit limit added by AddImplicitLimit rule. Rerank rerank = as(limit.child(), Rerank.class); - EsqlProject keep = as(rerank.child(), EsqlProject.class); - EsqlProject drop = as(keep.child(), EsqlProject.class); + Project keep = as(rerank.child(), Project.class); + Project drop = as(keep.child(), Project.class); Filter filter = as(drop.child(), Filter.class); EsRelation relation = as(filter.child(), EsRelation.class); @@ -4773,7 +4772,7 @@ public void testSubqueryInFrom() { Limit subqueryLimit = as(unionAll.children().get(0), Limit.class); Literal limitLiteral = as(subqueryLimit.limit(), Literal.class); assertEquals(1000, limitLiteral.value()); - EsqlProject subqueryProject = as(subqueryLimit.child(), EsqlProject.class); + Project subqueryProject = as(subqueryLimit.child(), Project.class); List projections = subqueryProject.projections(); assertEquals(13, projections.size()); // all fields from the two indices Eval subqueryEval = as(subqueryProject.child(), Eval.class); @@ -4793,7 +4792,7 @@ public void testSubqueryInFrom() { subqueryLimit = as(unionAll.children().get(1), Limit.class); limitLiteral = as(subqueryLimit.limit(), Literal.class); assertEquals(1000, limitLiteral.value()); - subqueryProject = as(subqueryLimit.child(), EsqlProject.class); + subqueryProject = as(subqueryLimit.child(), Project.class); projections = subqueryProject.projections(); assertEquals(13, projections.size()); // all fields from the two indices subqueryEval = as(subqueryProject.child(), Eval.class); @@ -4849,7 +4848,7 @@ public void testMultipleSubqueriesInFrom() { assertEquals("languageCode", mvExpandTarget.name()); ReferenceAttribute mvExpandExpanded = as(mvExpand.expanded(), ReferenceAttribute.class); assertEquals("languageCode", mvExpandExpanded.name()); - EsqlProject rename = as(mvExpand.child(), EsqlProject.class); + Project rename = as(mvExpand.child(), Project.class); List projections = rename.projections(); assertEquals(3, projections.size()); Alias a = as(projections.get(1), Alias.class); @@ -4883,7 +4882,7 @@ public void testMultipleSubqueriesInFrom() { Limit subqueryLimit = as(unionAll.children().get(0), Limit.class); Literal limitLiteral = as(subqueryLimit.limit(), Literal.class); assertEquals(1000, limitLiteral.value()); - EsqlProject subqueryProject = as(subqueryLimit.child(), EsqlProject.class); + Project subqueryProject = as(subqueryLimit.child(), Project.class); projections = subqueryProject.projections(); assertEquals(15, projections.size()); // all fields from the other legs Eval subqueryEval = as(subqueryProject.child(), Eval.class); @@ -4893,14 +4892,14 @@ public void testMultipleSubqueriesInFrom() { assertEquals("test", subqueryIndex.indexPattern()); subqueryLimit = as(unionAll.children().get(1), Limit.class); - subqueryProject = as(subqueryLimit.child(), EsqlProject.class); + subqueryProject = as(subqueryLimit.child(), Project.class); projections = subqueryProject.projections(); assertEquals(15, projections.size()); // all fields from the other legs subqueryEval = as(subqueryProject.child(), Eval.class); aliases = subqueryEval.fields(); // nullEvals from the other legs assertEquals(13, aliases.size()); Subquery subquery = as(subqueryEval.child(), Subquery.class); - rename = as(subquery.child(), EsqlProject.class); + rename = as(subquery.child(), Project.class); List renameProjections = rename.projections(); assertEquals(2, renameProjections.size()); FieldAttribute language_code = as(renameProjections.get(0), FieldAttribute.class); @@ -4919,7 +4918,7 @@ public void testMultipleSubqueriesInFrom() { assertEquals("languages", subqueryIndex.indexPattern()); subqueryLimit = as(unionAll.children().get(2), Limit.class); - subqueryProject = as(subqueryLimit.child(), EsqlProject.class); + subqueryProject = as(subqueryLimit.child(), Project.class); projections = subqueryProject.projections(); assertEquals(15, projections.size()); // all fields from the other legs subqueryEval = as(subqueryProject.child(), Eval.class); @@ -4931,7 +4930,7 @@ public void testMultipleSubqueriesInFrom() { assertEquals("sample_data", subqueryIndex.indexPattern()); subqueryLimit = as(unionAll.children().get(3), Limit.class); - subqueryProject = as(subqueryLimit.child(), EsqlProject.class); + subqueryProject = as(subqueryLimit.child(), Project.class); projections = subqueryProject.projections(); assertEquals(15, projections.size()); // all fields from the other legs subqueryEval = as(subqueryProject.child(), Eval.class); @@ -4964,7 +4963,7 @@ public void testMultipleSubqueryInFromWithoutMainIndexPattern() { assertEquals("languageCode", mvExpandTarget.name()); ReferenceAttribute mvExpandExpanded = as(mvExpand.expanded(), ReferenceAttribute.class); assertEquals("languageCode", mvExpandExpanded.name()); - EsqlProject rename = as(mvExpand.child(), EsqlProject.class); + Project rename = as(mvExpand.child(), Project.class); List projections = rename.projections(); assertEquals(3, projections.size()); Alias a = as(projections.get(1), Alias.class); @@ -4996,7 +4995,7 @@ public void testMultipleSubqueryInFromWithoutMainIndexPattern() { assertEquals(3, unionAll.children().size()); Limit subqueryLimit = as(unionAll.children().get(0), Limit.class); - EsqlProject subqueryProject = as(subqueryLimit.child(), EsqlProject.class); + Project subqueryProject = as(subqueryLimit.child(), Project.class); projections = subqueryProject.projections(); assertEquals(15, projections.size()); // all fields from the other legs Eval subqueryEval = as(subqueryProject.child(), Eval.class); @@ -5011,14 +5010,14 @@ public void testMultipleSubqueryInFromWithoutMainIndexPattern() { assertEquals("test", subqueryIndex.indexPattern()); subqueryLimit = as(unionAll.children().get(1), Limit.class); - subqueryProject = as(subqueryLimit.child(), EsqlProject.class); + subqueryProject = as(subqueryLimit.child(), Project.class); projections = subqueryProject.projections(); assertEquals(15, projections.size()); // all fields from the other legs subqueryEval = as(subqueryProject.child(), Eval.class); aliases = subqueryEval.fields(); // nullEvals from the other legs assertEquals(13, aliases.size()); subquery = as(subqueryEval.child(), Subquery.class); - rename = as(subquery.child(), EsqlProject.class); + rename = as(subquery.child(), Project.class); List renameProjections = rename.projections(); assertEquals(2, renameProjections.size()); FieldAttribute language_code = as(renameProjections.get(0), FieldAttribute.class); @@ -5037,7 +5036,7 @@ public void testMultipleSubqueryInFromWithoutMainIndexPattern() { assertEquals("languages", subqueryIndex.indexPattern()); subqueryLimit = as(unionAll.children().get(2), Limit.class); - subqueryProject = as(subqueryLimit.child(), EsqlProject.class); + subqueryProject = as(subqueryLimit.child(), Project.class); projections = subqueryProject.projections(); assertEquals(15, projections.size()); // all fields from the other legs subqueryEval = as(subqueryProject.child(), Eval.class); @@ -5065,12 +5064,12 @@ public void testNestedSubqueryInFrom() { assertEquals(2, unionAll.children().size()); Limit subqueryLimit = as(unionAll.children().get(0), Limit.class); - EsqlProject subqueryProject = as(subqueryLimit.child(), EsqlProject.class); + Project subqueryProject = as(subqueryLimit.child(), Project.class); Eval subqueryEval = as(subqueryProject.child(), Eval.class); EsRelation subqueryIndex = as(subqueryEval.child(), EsRelation.class); assertEquals("test", subqueryIndex.indexPattern()); subqueryLimit = as(unionAll.children().get(1), Limit.class); - subqueryProject = as(subqueryLimit.child(), EsqlProject.class); + subqueryProject = as(subqueryLimit.child(), Project.class); subqueryEval = as(subqueryProject.child(), Eval.class); Subquery subquery = as(subqueryEval.child(), Subquery.class); Filter subqueryFilter = as(subquery.child(), Filter.class); @@ -5078,13 +5077,13 @@ public void testNestedSubqueryInFrom() { assertEquals(2, unionAll.children().size()); subqueryLimit = as(unionAll.children().get(0), Limit.class); - subqueryProject = as(subqueryLimit.child(), EsqlProject.class); + subqueryProject = as(subqueryLimit.child(), Project.class); subqueryEval = as(subqueryProject.child(), Eval.class); subqueryIndex = as(subqueryEval.child(), EsRelation.class); assertEquals("languages", subqueryIndex.indexPattern()); subqueryLimit = as(unionAll.children().get(1), Limit.class); - subqueryProject = as(subqueryLimit.child(), EsqlProject.class); + subqueryProject = as(subqueryLimit.child(), Project.class); subqueryEval = as(subqueryProject.child(), Eval.class); subquery = as(subqueryEval.child(), Subquery.class); Aggregate subqueryAggregate = as(subquery.child(), Aggregate.class); @@ -5107,7 +5106,7 @@ public void testNestedSubqueryInFromWithMetadata() { assertEquals(2, unionAll.children().size()); Limit subqueryLimit = as(unionAll.children().get(0), Limit.class); - EsqlProject subqueryProject = as(subqueryLimit.child(), EsqlProject.class); + Project subqueryProject = as(subqueryLimit.child(), Project.class); Eval subqueryEval = as(subqueryProject.child(), Eval.class); EsRelation subqueryIndex = as(subqueryEval.child(), EsRelation.class); assertEquals("test", subqueryIndex.indexPattern()); @@ -5117,7 +5116,7 @@ public void testNestedSubqueryInFromWithMetadata() { assertEquals("_index", metadataAttribute.name()); subqueryLimit = as(unionAll.children().get(1), Limit.class); - subqueryProject = as(subqueryLimit.child(), EsqlProject.class); + subqueryProject = as(subqueryLimit.child(), Project.class); subqueryEval = as(subqueryProject.child(), Eval.class); Subquery subquery = as(subqueryEval.child(), Subquery.class); Filter subqueryFilter = as(subquery.child(), Filter.class); @@ -5125,7 +5124,7 @@ public void testNestedSubqueryInFromWithMetadata() { assertEquals(2, unionAll.children().size()); subqueryLimit = as(unionAll.children().get(0), Limit.class); - subqueryProject = as(subqueryLimit.child(), EsqlProject.class); + subqueryProject = as(subqueryLimit.child(), Project.class); subqueryEval = as(subqueryProject.child(), Eval.class); subqueryIndex = as(subqueryEval.child(), EsRelation.class); assertEquals("languages", subqueryIndex.indexPattern()); @@ -5133,7 +5132,7 @@ public void testNestedSubqueryInFromWithMetadata() { assertEquals(2, output.size()); subqueryLimit = as(unionAll.children().get(1), Limit.class); - subqueryProject = as(subqueryLimit.child(), EsqlProject.class); + subqueryProject = as(subqueryLimit.child(), Project.class); subqueryEval = as(subqueryProject.child(), Eval.class); subquery = as(subqueryEval.child(), Subquery.class); Aggregate subqueryAggregate = as(subquery.child(), Aggregate.class); @@ -5171,13 +5170,13 @@ public void testNestedSubqueriesInFromWithoutMainIndexPattern() { assertEquals(2, unionAll.children().size()); Limit subqueryLimit = as(unionAll.children().get(0), Limit.class); - EsqlProject subqueryProject = as(subqueryLimit.child(), EsqlProject.class); + Project subqueryProject = as(subqueryLimit.child(), Project.class); Eval subqueryEval = as(subqueryProject.child(), Eval.class); EsRelation subqueryIndex = as(subqueryEval.child(), EsRelation.class); assertEquals("test", subqueryIndex.indexPattern()); subqueryLimit = as(unionAll.children().get(1), Limit.class); - subqueryProject = as(subqueryLimit.child(), EsqlProject.class); + subqueryProject = as(subqueryLimit.child(), Project.class); subqueryEval = as(subqueryProject.child(), Eval.class); Subquery subquery = as(subqueryEval.child(), Subquery.class); Aggregate subqueryAggregate = as(subquery.child(), Aggregate.class); @@ -5218,7 +5217,7 @@ public void testMixedDataTypesInSubquery() { assertEquals(2, unionAll.children().size()); Limit subqueryLimit = as(unionAll.children().get(0), Limit.class); - EsqlProject subqueryProject = as(subqueryLimit.child(), EsqlProject.class); + Project subqueryProject = as(subqueryLimit.child(), Project.class); Eval implicitCastingEval = as(subqueryProject.child(), Eval.class); assertEquals(10, implicitCastingEval.fields().size()); Eval explicitCastingEval = as(implicitCastingEval.child(), Eval.class); @@ -5229,7 +5228,7 @@ public void testMixedDataTypesInSubquery() { assertEquals("test", subqueryIndex.indexPattern()); subqueryLimit = as(unionAll.children().get(1), Limit.class); - subqueryProject = as(subqueryLimit.child(), EsqlProject.class); + subqueryProject = as(subqueryLimit.child(), Project.class); implicitCastingEval = as(subqueryProject.child(), Eval.class); assertEquals(9, implicitCastingEval.fields().size()); explicitCastingEval = as(implicitCastingEval.child(), Eval.class); @@ -5289,7 +5288,7 @@ public void testMixedDataTypesWithExplicitCastingInSubquery() { assertEquals(2, unionAll.children().size()); Limit subqueryLimit = as(unionAll.children().get(0), Limit.class); - EsqlProject subqueryProject = as(subqueryLimit.child(), EsqlProject.class); + Project subqueryProject = as(subqueryLimit.child(), Project.class); Eval implicitCastingEval = as(subqueryProject.child(), Eval.class); assertEquals(10, implicitCastingEval.fields().size()); Eval explicitCastingEval = as(implicitCastingEval.child(), Eval.class); @@ -5300,7 +5299,7 @@ public void testMixedDataTypesWithExplicitCastingInSubquery() { assertEquals("test", subqueryIndex.indexPattern()); subqueryLimit = as(unionAll.children().get(1), Limit.class); - subqueryProject = as(subqueryLimit.child(), EsqlProject.class); + subqueryProject = as(subqueryLimit.child(), Project.class); implicitCastingEval = as(subqueryProject.child(), Eval.class); assertEquals(9, implicitCastingEval.fields().size()); explicitCastingEval = as(implicitCastingEval.child(), Eval.class); @@ -5372,7 +5371,7 @@ public void testMixedDataTypesWithMultipleExplicitCastingInSubquery() { assertEquals(2, unionAll.children().size()); Limit subqueryLimit = as(unionAll.children().get(0), Limit.class); - EsqlProject subqueryProject = as(subqueryLimit.child(), EsqlProject.class); + Project subqueryProject = as(subqueryLimit.child(), Project.class); Eval implicitCastingEval = as(subqueryProject.child(), Eval.class); assertEquals(10, implicitCastingEval.fields().size()); Eval explicitCastingEval = as(implicitCastingEval.child(), Eval.class); @@ -5383,7 +5382,7 @@ public void testMixedDataTypesWithMultipleExplicitCastingInSubquery() { assertEquals("test", subqueryIndex.indexPattern()); subqueryLimit = as(unionAll.children().get(1), Limit.class); - subqueryProject = as(subqueryLimit.child(), EsqlProject.class); + subqueryProject = as(subqueryLimit.child(), Project.class); implicitCastingEval = as(subqueryProject.child(), Eval.class); assertEquals(9, implicitCastingEval.fields().size()); explicitCastingEval = as(implicitCastingEval.child(), Eval.class); @@ -5436,7 +5435,7 @@ public void testSubqueryWithUnionAllOutputOverwritten() { assertEquals(2, unionAll.children().size()); Limit subqueryLimit = as(unionAll.children().get(0), Limit.class); - EsqlProject subqueryProject = as(subqueryLimit.child(), EsqlProject.class); + Project subqueryProject = as(subqueryLimit.child(), Project.class); Eval implicitCastingEval = as(subqueryProject.child(), Eval.class); Eval explicitCastingEval = as(implicitCastingEval.child(), Eval.class); Eval missingFieldEval = as(explicitCastingEval.child(), Eval.class); @@ -5444,7 +5443,7 @@ public void testSubqueryWithUnionAllOutputOverwritten() { assertEquals("test", subqueryIndex.indexPattern()); subqueryLimit = as(unionAll.children().get(1), Limit.class); - subqueryProject = as(subqueryLimit.child(), EsqlProject.class); + subqueryProject = as(subqueryLimit.child(), Project.class); implicitCastingEval = as(subqueryProject.child(), Eval.class); explicitCastingEval = as(implicitCastingEval.child(), Eval.class); missingFieldEval = as(explicitCastingEval.child(), Eval.class); @@ -5475,24 +5474,24 @@ public void testSubqueryWithTimeSeriesIndexInMainQuery() { assertEquals(3, unionAll.children().size()); limit = as(unionAll.children().get(0), Limit.class); - EsqlProject esqlProject = as(limit.child(), EsqlProject.class); - Eval eval = as(esqlProject.child(), Eval.class); + Project project = as(limit.child(), Project.class); + Eval eval = as(project.child(), Eval.class); eval = as(eval.child(), Eval.class); EsRelation relation = as(eval.child(), EsRelation.class); assertEquals("k8s", relation.indexPattern()); assertEquals(IndexMode.STANDARD, relation.indexMode()); limit = as(unionAll.children().get(1), Limit.class); - esqlProject = as(limit.child(), EsqlProject.class); - eval = as(esqlProject.child(), Eval.class); + project = as(limit.child(), Project.class); + eval = as(project.child(), Eval.class); Subquery subquery = as(eval.child(), Subquery.class); relation = as(subquery.child(), EsRelation.class); assertEquals("sample_data", relation.indexPattern()); assertEquals(IndexMode.STANDARD, relation.indexMode()); limit = as(unionAll.children().get(2), Limit.class); - esqlProject = as(limit.child(), EsqlProject.class); - eval = as(esqlProject.child(), Eval.class); + project = as(limit.child(), Project.class); + eval = as(project.child(), Eval.class); subquery = as(eval.child(), Subquery.class); filter = as(subquery.child(), Filter.class); relation = as(filter.child(), EsRelation.class); @@ -5517,15 +5516,15 @@ public void testSubqueryWithTimeSeriesIndexInSubquery() { assertEquals(3, unionAll.children().size()); limit = as(unionAll.children().get(0), Limit.class); - EsqlProject esqlProject = as(limit.child(), EsqlProject.class); - Eval eval = as(esqlProject.child(), Eval.class); + Project project = as(limit.child(), Project.class); + Eval eval = as(project.child(), Eval.class); EsRelation relation = as(eval.child(), EsRelation.class); assertEquals("sample_data", relation.indexPattern()); assertEquals(IndexMode.STANDARD, relation.indexMode()); limit = as(unionAll.children().get(1), Limit.class); - esqlProject = as(limit.child(), EsqlProject.class); - eval = as(esqlProject.child(), Eval.class); + project = as(limit.child(), Project.class); + eval = as(project.child(), Eval.class); eval = as(eval.child(), Eval.class); Subquery subquery = as(eval.child(), Subquery.class); InlineStats inlineStats = as(subquery.child(), InlineStats.class); @@ -5536,8 +5535,8 @@ public void testSubqueryWithTimeSeriesIndexInSubquery() { assertEquals(IndexMode.STANDARD, relation.indexMode()); limit = as(unionAll.children().get(2), Limit.class); - esqlProject = as(limit.child(), EsqlProject.class); - eval = as(esqlProject.child(), Eval.class); + project = as(limit.child(), Project.class); + eval = as(project.child(), Eval.class); subquery = as(eval.child(), Subquery.class); filter = as(subquery.child(), Filter.class); relation = as(filter.child(), EsRelation.class); @@ -5562,16 +5561,16 @@ public void testSubqueryWithTimeSeriesIndexInMainQueryAndSubquery() { assertEquals(3, unionAll.children().size()); limit = as(unionAll.children().get(0), Limit.class); - EsqlProject esqlProject = as(limit.child(), EsqlProject.class); - Eval eval = as(esqlProject.child(), Eval.class); + Project project = as(limit.child(), Project.class); + Eval eval = as(project.child(), Eval.class); eval = as(eval.child(), Eval.class); EsRelation relation = as(eval.child(), EsRelation.class); assertEquals("k8s", relation.indexPattern()); assertEquals(IndexMode.STANDARD, relation.indexMode()); limit = as(unionAll.children().get(1), Limit.class); - esqlProject = as(limit.child(), EsqlProject.class); - eval = as(esqlProject.child(), Eval.class); + project = as(limit.child(), Project.class); + eval = as(project.child(), Eval.class); eval = as(eval.child(), Eval.class); Subquery subquery = as(eval.child(), Subquery.class); InlineStats inlineStats = as(subquery.child(), InlineStats.class); @@ -5582,8 +5581,8 @@ public void testSubqueryWithTimeSeriesIndexInMainQueryAndSubquery() { assertEquals(IndexMode.STANDARD, relation.indexMode()); limit = as(unionAll.children().get(2), Limit.class); - esqlProject = as(limit.child(), EsqlProject.class); - eval = as(esqlProject.child(), Eval.class); + project = as(limit.child(), Project.class); + eval = as(project.child(), Eval.class); subquery = as(eval.child(), Subquery.class); filter = as(subquery.child(), Filter.class); relation = as(filter.child(), EsRelation.class); @@ -5612,12 +5611,12 @@ public void testSubqueryWithFullTextFunctionInMainQuery() { assertEquals(2, unionAll.children().size()); Limit subqueryLimit = as(unionAll.children().get(0), Limit.class); - EsqlProject subqueryProject = as(subqueryLimit.child(), EsqlProject.class); + Project subqueryProject = as(subqueryLimit.child(), Project.class); EsRelation subqueryIndex = as(subqueryProject.child(), EsRelation.class); assertEquals("sample_data", subqueryIndex.indexPattern()); subqueryLimit = as(unionAll.children().get(1), Limit.class); - subqueryProject = as(subqueryLimit.child(), EsqlProject.class); + subqueryProject = as(subqueryLimit.child(), Project.class); Subquery subquery = as(subqueryProject.child(), Subquery.class); Filter subqueryFilter = as(subquery.child(), Filter.class); MatchOperator matchOperator = as(subqueryFilter.condition(), MatchOperator.class); @@ -5647,12 +5646,12 @@ public void testPruneEmptySubquery() { // the subquery with remote:missingIndex is pruned, validate PruneEmptyUnionAllBranch assertEquals(2, unionAll.children().size()); Limit subqueryLimit = as(unionAll.children().get(0), Limit.class); - EsqlProject subqueryProject = as(subqueryLimit.child(), EsqlProject.class); + Project subqueryProject = as(subqueryLimit.child(), Project.class); Eval subqueryEval = as(subqueryProject.child(), Eval.class); EsRelation subqueryIndex = as(subqueryEval.child(), EsRelation.class); assertEquals("test", subqueryIndex.indexPattern()); subqueryLimit = as(unionAll.children().get(1), Limit.class); - subqueryProject = as(subqueryLimit.child(), EsqlProject.class); + subqueryProject = as(subqueryLimit.child(), Project.class); subqueryEval = as(subqueryProject.child(), Eval.class); Subquery subquery = as(subqueryEval.child(), Subquery.class); subqueryIndex = as(subquery.child(), EsRelation.class); @@ -5675,7 +5674,7 @@ public void testLookupJoinOnFieldNotAnywhereElse() { assertThat(limit.limit(), instanceOf(Literal.class)); assertEquals(1000, as(limit.limit(), Literal.class).value()); - EsqlProject project = as(limit.child(), EsqlProject.class); + Project project = as(limit.child(), Project.class); assertEquals(1, project.projections().size()); LookupJoin lookupJoin = as(project.child(), LookupJoin.class); diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/VerifierTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/VerifierTests.java index d745a9662d2c2..4f3cb4f464b93 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/VerifierTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/VerifierTests.java @@ -293,6 +293,24 @@ public void testUnsupportedAndMultiTypedFields() { error("from test* | rename multi_typed as x", analyzer) ); + // Verify that UnsupportedAttribute can pass through KEEP (Project) unchanged without error. + // This is valid because the field is just being projected, not used in operations. + query("from test* | keep unsupported", analyzer); + query("from test* | keep multi_typed", analyzer); + + // Verify that renaming UnsupportedAttribute fails even after passing through KEEP. + // This validates the fix for EsqlProject consolidation: the rename check runs unconditionally, + // not gated by Project.expressionsResolved() which treats UnsupportedAttribute as resolved. + assertEquals( + "1:40: Cannot use field [unsupported] with unsupported type [flattened]", + error("from test* | keep unsupported | rename unsupported as x", analyzer) + ); + assertEquals( + "1:40: Cannot use field [multi_typed] due to ambiguities being mapped as [2] incompatible types:" + + " [ip] in [test1, test2, test3] and [2] other indices, [keyword] in [test6]", + error("from test* | keep multi_typed | rename multi_typed as x", analyzer) + ); + assertEquals( "1:19: Cannot use field [unsupported] with unsupported type [flattened]", error("from test* | sort unsupported asc", analyzer) diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/HoistOrderByBeforeInlineJoinOptimizerTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/HoistOrderByBeforeInlineJoinOptimizerTests.java index 68e1a1109e525..837a49930bdb4 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/HoistOrderByBeforeInlineJoinOptimizerTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/HoistOrderByBeforeInlineJoinOptimizerTests.java @@ -30,7 +30,6 @@ import org.elasticsearch.xpack.esql.plan.logical.join.Join; import org.elasticsearch.xpack.esql.plan.logical.join.JoinTypes; import org.elasticsearch.xpack.esql.plan.logical.join.StubRelation; -import org.elasticsearch.xpack.esql.plan.logical.local.EsqlProject; import java.util.List; import java.util.Set; @@ -50,7 +49,7 @@ public class HoistOrderByBeforeInlineJoinOptimizerTests extends AbstractLogicalPlanOptimizerTests { /* - * EsqlProject[[emp_no{f}#12, avg{r}#6, languages{f}#15, gender{f}#14]] + * Project[[emp_no{f}#12, avg{r}#6, languages{f}#15, gender{f}#14]] * \_TopN[[Order[emp_no{f}#12,ASC,LAST]],5[INTEGER],false] * \_InlineJoin[LEFT,[languages{f}#15],[languages{r}#15]] * |_EsRelation[employees][_meta_field{f}#18, emp_no{f}#12, first_name{f}#13, ..] @@ -74,9 +73,9 @@ public void testInlineStatsAfterSortAndBeforeLimit() { } var plan = optimizedPlan(query); - var esqlProject = as(plan, EsqlProject.class); + var project = as(plan, Project.class); - var topN = as(esqlProject.child(), TopN.class); + var topN = as(project.child(), TopN.class); assertThat(topN.order().size(), is(1)); var order = as(topN.order().get(0), Order.class); assertThat(order.direction(), equalTo(Order.OrderDirection.ASC)); @@ -90,7 +89,7 @@ public void testInlineStatsAfterSortAndBeforeLimit() { var relation = as(inlineJoin.left(), EsRelation.class); assertThat(relation.concreteQualifiedIndices(), is(Set.of("employees"))); // Right - var project = as(inlineJoin.right(), Project.class); + project = as(inlineJoin.right(), Project.class); assertThat(Expressions.names(project.projections()), is(List.of("avg", "languages"))); var eval = as(project.child(), Eval.class); assertThat(Expressions.names(eval.fields()), is(List.of("avg"))); @@ -155,7 +154,7 @@ public void testInlineStatsAfterSort() { /* * TopN[[Order[emp_no{f}#17,DESC,FIRST]],1000[INTEGER],false] * \_InlineJoin[LEFT,[emp_no{f}#17],[emp_no{r}#17]] - * |_EsqlProject[[_meta_field{f}#23, emp_no{f}#17, first_name{f}#18, gender{f}#19, hire_date{f}#24, job{f}#25, job.raw{f}#26, + * |_Project[[_meta_field{f}#23, emp_no{f}#17, first_name{f}#18, gender{f}#19, hire_date{f}#24, job{f}#25, job.raw{f}#26, * languages{f}#20, last_name{f}#21 AS lName#11, long_noidx{f}#27, salary{f}#22, msg{r}#4, salaryK{r}#8]] * | \_Eval[[salary{f}#22 / 1000[INTEGER] AS salaryK#8]] * | \_Dissect[first_name{f}#18,Parser[pattern=%{msg}, appendSeparator=, parser=org.elasticsearch.dissect.DissectParser@3f4941c9], @@ -199,8 +198,8 @@ public void testInlineStatsAfterSortAndSortAgnostic() { assertThat(Expressions.names(inlineJoin.config().rightFields()), is(List.of("emp_no"))); // Left side of the join - var esqlProject = as(inlineJoin.left(), EsqlProject.class); - var eval = as(esqlProject.child(), Eval.class); + var project = as(inlineJoin.left(), Project.class); + var eval = as(project.child(), Eval.class); assertThat(Expressions.names(eval.fields()), is(List.of("salaryK"))); var dissect = as(eval.child(), Dissect.class); assertThat(dissect.parser().pattern(), is("%{msg}")); @@ -215,7 +214,7 @@ public void testInlineStatsAfterSortAndSortAgnostic() { assertThat(esRelation.concreteQualifiedIndices(), is(Set.of("employees"))); // Right side of the join - var project = as(inlineJoin.right(), Project.class); + project = as(inlineJoin.right(), Project.class); assertThat(Expressions.names(project.projections()), is(List.of("avg", "emp_no"))); var rightEval = as(project.child(), Eval.class); assertThat(Expressions.names(rightEval.fields()), is(List.of("avg"))); @@ -468,7 +467,7 @@ public void testInlineStatsAfterTriSortPartlyShaddowed() { * languages{f}#15, last_name{f}#16, long_noidx{f}#22, salary{f}#17, cd{r}#11]] * \_TopN[[Order[$$s1$temp_name$23{r}#24,ASC,LAST]],1000[INTEGER],false] * \_InlineJoin[LEFT,[],[]] - * |_EsqlProject[[_meta_field{f}#18, emp_no{f}#12, first_name{f}#13, gender{f}#14, hire_date{f}#19, job{f}#20, job.raw{f}#21, + * |_Project[[_meta_field{f}#18, emp_no{f}#12, first_name{f}#13, gender{f}#14, hire_date{f}#19, job{f}#20, job.raw{f}#21, * languages{f}#15, last_name{f}#16, long_noidx{f}#22, salary{f}#17, $$s1$temp_name$23{r}#24]] * | \_Eval[[s1{r}#5 AS $$s1$temp_name$23#24]] * | \_Filter[s1{r}#5 > 50000[INTEGER]] @@ -509,7 +508,7 @@ public void testInlineStatsAfterSortDropped() { assertThat(inlineJoin.config().rightFields(), empty()); // Left side of the join - var leftProject = as(inlineJoin.left(), EsqlProject.class); + var leftProject = as(inlineJoin.left(), Project.class); var leftEval = as(leftProject.child(), Eval.class); assertThat(Expressions.names(leftEval.fields()), contains(startsWith("$$s1$temp_name$"))); var leftFilter = as(leftEval.child(), Filter.class); @@ -535,7 +534,7 @@ public void testInlineStatsAfterSortDropped() { * Project[[salary{r}#7, emp_no{f}#9]] * \_TopN[[Order[$$salary$temp_name$20{r}#21,ASC,LAST]],1000[INTEGER],false] * \_InlineJoin[LEFT,[emp_no{f}#9],[emp_no{r}#9]] - * |_EsqlProject[[salary{f}#14, emp_no{f}#9, $$salary$temp_name$20{r}#21]] + * |_Project[[salary{f}#14, emp_no{f}#9, $$salary$temp_name$20{r}#21]] * | \_Eval[[salary{f}#14 AS $$salary$temp_name$20#21]] * | \_EsRelation[employees][_meta_field{f}#15, emp_no{f}#9, first_name{f}#10, g..] * \_Aggregate[[emp_no{f}#9],[COUNT(*[KEYWORD],true[BOOLEAN],PT0S[TIME_DURATION]) AS salary#7, emp_no{f}#9]] @@ -570,7 +569,7 @@ public void testShadowingInlineStatsAfterSort() { assertThat(Expressions.names(inlineJoin.config().rightFields()), is(List.of("emp_no"))); // Left side of the join - var leftProject = as(inlineJoin.left(), EsqlProject.class); + var leftProject = as(inlineJoin.left(), Project.class); var leftEval = as(leftProject.child(), Eval.class); assertThat(Expressions.names(leftEval.fields()), contains(startsWith("$$salary$temp_name$"))); var relation = as(leftEval.child(), EsRelation.class); @@ -590,7 +589,7 @@ public void testShadowingInlineStatsAfterSort() { * Project[[salary{r}#8, emp_no{f}#10]] * \_TopN[[Order[$$salary$temp_name$21{r}#22,ASC,LAST], Order[emp_no{f}#10,ASC,LAST]],1000[INTEGER],false] * \_InlineJoin[LEFT,[emp_no{f}#10],[emp_no{r}#10]] - * |_EsqlProject[[salary{f}#15, emp_no{f}#10, $$salary$temp_name$21{r}#22]] + * |_Project[[salary{f}#15, emp_no{f}#10, $$salary$temp_name$21{r}#22]] * | \_Eval[[salary{f}#15 AS $$salary$temp_name$21#22]] * | \_EsRelation[employees][_meta_field{f}#16, emp_no{f}#10, first_name{f}#11, ..] * \_Aggregate[[emp_no{f}#10],[COUNT(*[KEYWORD],true[BOOLEAN],PT0S[TIME_DURATION]) AS salary#8, emp_no{f}#10]] @@ -631,7 +630,7 @@ public void testMixedShadowingInlineStatsAfterSort() { assertThat(Expressions.names(inlineJoin.config().rightFields()), is(List.of("emp_no"))); // Left side of the join - var leftProject = as(inlineJoin.left(), EsqlProject.class); + var leftProject = as(inlineJoin.left(), Project.class); var leftEval = as(leftProject.child(), Eval.class); assertThat(Expressions.names(leftEval.fields()), contains(startsWith("$$salary$temp_name$"))); var relation = as(leftEval.child(), EsRelation.class); @@ -651,7 +650,7 @@ public void testMixedShadowingInlineStatsAfterSort() { * Project[[salary{r}#12, emp_no{f}#14]] * \_TopN[[Order[$$salary$temp_name$25{r}#26,ASC,LAST], Order[$$s1$temp_name$27{r}#28,ASC,LAST]],1000[INTEGER],false] * \_InlineJoin[LEFT,[emp_no{f}#14],[emp_no{r}#14]] - * |_EsqlProject[[salary{f}#19, emp_no{f}#14, $$salary$temp_name$25{r}#26, $$s1$temp_name$27{r}#28]] + * |_Project[[salary{f}#19, emp_no{f}#14, $$salary$temp_name$25{r}#26, $$s1$temp_name$27{r}#28]] * | \_Eval[[salary{f}#19 + 1[INTEGER] AS s1#7, salary{f}#19 AS $$salary$temp_name$25#26, s1{r}#7 AS $$s1$temp_name$27#28]] * | \_EsRelation[employees][_meta_field{f}#20, emp_no{f}#14, first_name{f}#15, ..] * \_Aggregate[[emp_no{f}#14],[COUNT(*[KEYWORD],true[BOOLEAN],PT0S[TIME_DURATION]) AS salary#12, emp_no{f}#14]] @@ -694,7 +693,7 @@ public void testShadowingInlineStatsAfterSortAndDrop() { assertThat(Expressions.names(inlineJoin.config().rightFields()), is(List.of("emp_no"))); // Left side of the join - var leftProject = as(inlineJoin.left(), EsqlProject.class); + var leftProject = as(inlineJoin.left(), Project.class); var leftEval = as(leftProject.child(), Eval.class); assertThat( Expressions.names(leftEval.fields()), @@ -717,7 +716,7 @@ public void testShadowingInlineStatsAfterSortAndDrop() { * Project[[emp_idx{r}#9, salary{f}#20, sum{r}#13, languages{f}#18]] * \_TopN[[Order[$$emp_no$temp_name$27{r}#28,ASC,LAST]],1000[INTEGER],false] * \_InlineJoin[LEFT,[languages{f}#18],[languages{r}#18]] - * |_EsqlProject[[emp_no{f}#15 AS emp_idx#9, salary{f}#20, languages{f}#18, $$emp_no$temp_name$27{r}#28]] + * |_Project[[emp_no{f}#15 AS emp_idx#9, salary{f}#20, languages{f}#18, $$emp_no$temp_name$27{r}#28]] * | \_Eval[[emp_no{f}#15 AS $$emp_no$temp_name$27#28]] * | \_EsRelation[employees][_meta_field{f}#21, emp_no{f}#15, first_name{f}#16, ..] * \_Project[[sum{r}#13, languages{f}#18]] @@ -756,7 +755,7 @@ public void testInlineStatsWithAggExpressionAfterSortAndRename() { assertThat(Expressions.names(inlineJoin.config().rightFields()), is(List.of("languages"))); // Left side of the join - var leftProject = as(inlineJoin.left(), EsqlProject.class); + var leftProject = as(inlineJoin.left(), Project.class); var leftEval = as(leftProject.child(), Eval.class); assertThat(Expressions.names(leftEval.fields()), contains(startsWith("$$emp_no$temp_name$"))); var relation = as(leftEval.child(), EsRelation.class); @@ -957,7 +956,7 @@ public void testInlineStatsAfterEvalAndSortAndStats() { * Project[[emp_no{f}#22, first_name{f}#23, sal{r}#17, id{r}#13, language_code{r}#36, language_name{r}#37, cd{r}#20, languages{f}#25]] * \_TopN[[Order[$$language_name$temp_name$38$temp_name$40{r}#41,ASC,LAST]],1000[INTEGER],false] * \_InlineJoin[LEFT,[languages{f}#25],[languages{r}#25]] - * |_EsqlProject[[emp_no{f}#22, first_name{f}#23, salary{f}#27 AS sal#17, languages{f}#25, id{r}#13, language_code{r}#36, + * |_Project[[emp_no{f}#22, first_name{f}#23, salary{f}#27 AS sal#17, languages{f}#25, id{r}#13, language_code{r}#36, * language_name{r}#37, $$language_name$temp_name$38$temp_name$40{r}#41]] * | \_Eval[[$$language_name$temp_name$38{r$}#39 AS $$language_name$temp_name$38$temp_name$40#41]] * | \_Enrich[ANY,languages_idx[KEYWORD],id{r}#13,{"match":{"indices":[],"match_field":"id", @@ -1004,7 +1003,7 @@ public void testInlineStatsAfterEnrichAndSort() { assertThat(Expressions.names(inlineJoin.config().rightFields()), is(List.of("languages"))); // Left side of the join - var leftProject = as(inlineJoin.left(), EsqlProject.class); + var leftProject = as(inlineJoin.left(), Project.class); var leftEval = as(leftProject.child(), Eval.class); assertThat(Expressions.names(leftEval.fields()), contains(startsWith("$$language_name$temp_name$"))); var enrich = as(leftEval.child(), Enrich.class); diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/LocalLogicalPlanOptimizerTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/LocalLogicalPlanOptimizerTests.java index 2d3e7a331e443..8cd5fb7a8518d 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/LocalLogicalPlanOptimizerTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/LocalLogicalPlanOptimizerTests.java @@ -86,7 +86,6 @@ import org.elasticsearch.xpack.esql.plan.logical.join.JoinTypes; import org.elasticsearch.xpack.esql.plan.logical.join.StubRelation; import org.elasticsearch.xpack.esql.plan.logical.local.EmptyLocalSupplier; -import org.elasticsearch.xpack.esql.plan.logical.local.EsqlProject; import org.elasticsearch.xpack.esql.plan.logical.local.LocalRelation; import org.elasticsearch.xpack.esql.plan.physical.EsSourceExec; import org.elasticsearch.xpack.esql.plan.physical.EvalExec; @@ -252,7 +251,7 @@ public void testReassignedMissingFieldInProject() { /** * Expects - * EsqlProject[[first_name{f}#4]] + * Project[[first_name{f}#4]] * \_Limit[10000[INTEGER]] * \_EsRelation[test][_meta_field{f}#9, emp_no{f}#3, first_name{f}#4, !ge..] */ @@ -277,7 +276,7 @@ public void testMissingFieldInSort() { /** * Expects - * EsqlProject[[first_name{f}#7, last_name{r}#17]] + * Project[[first_name{f}#7, last_name{r}#17]] * \_Limit[1000[INTEGER],true] * \_MvExpand[last_name{f}#10,last_name{r}#17] * \_Project[[_meta_field{f}#12, emp_no{f}#6, first_name{f}#7, gender{f}#8, hire_date{f}#13, job{f}#14, job.raw{f}#15, lang @@ -298,7 +297,7 @@ public void testMissingFieldInMvExpand() { // It'd be much better if this project was pushed down past the MvExpand, because MvExpand's cost scales with the number of // involved attributes/columns. - var project = as(localPlan, EsqlProject.class); + var project = as(localPlan, Project.class); var projections = project.projections(); assertThat(Expressions.names(projections), contains("first_name", "last_name")); @@ -405,7 +404,7 @@ public void testMissingFieldInNewCommand() { /** * Expects - * EsqlProject[[x{r}#3]] + * Project[[x{r}#3]] * \_Eval[[null[INTEGER] AS x]] * \_Limit[10000[INTEGER]] * \_EsRelation[test][_meta_field{f}#11, emp_no{f}#5, first_name{f}#6, !g..] @@ -1084,7 +1083,7 @@ public void testPruneLeftJoinOnNullMatchingFieldAndShadowingAttributes() { /** * Expected: - * EsqlProject[[!alias_integer, boolean{f}#7, byte{f}#8, constant_keyword-foo{f}#9, date{f}#10, date_nanos{f}#11, dense_vector + * Project[[!alias_integer, boolean{f}#7, byte{f}#8, constant_keyword-foo{f}#9, date{f}#10, date_nanos{f}#11, dense_vector * {f}#26, double{f}#12, float{f}#13, half_float{f}#14, integer{f}#16, ip{f}#17, keyword{f}#18, long{f}#19, scaled_float{f}#15, * semantic_text{f}#25, short{f}#21, text{f}#22, unsigned_long{f}#20, version{f}#23, wildcard{f}#24, s{r}#5]] * \_Eval[[$$dense_vector$V_DOT_PRODUCT$27{f}#27 AS s#5]] @@ -1100,8 +1099,8 @@ public void testVectorFunctionsReplaced() { LogicalPlan plan = localPlan(plan(query, allTypesAnalyzer), TEST_SEARCH_STATS); - // EsqlProject[[!alias_integer, boolean{f}#7, byte{f}#8, ... s{r}#5]] - var project = as(plan, EsqlProject.class); + // Project[[!alias_integer, boolean{f}#7, byte{f}#8, ... s{r}#5]] + var project = as(plan, Project.class); // Does not contain the extracted field assertFalse(Expressions.names(project.projections()).stream().anyMatch(s -> s.startsWith(testCase.toFieldAttrName()))); @@ -1131,7 +1130,7 @@ public void testVectorFunctionsReplaced() { /** * Expected: - * EsqlProject[[s{r}#4]] + * Project[[s{r}#4]] * \_TopN[[Order[s{r}#4,DESC,FIRST]],1[INTEGER]] * \_Eval[[$$dense_vector$replaced$28{t}#28 AS s#4]] * \_EsRelation[types][$$dense_vector$replaced$28{t}#28, !alias_integer, b..] @@ -1148,8 +1147,8 @@ public void testVectorFunctionsReplacedWithTopN() { LogicalPlan plan = localPlan(plan(query, allTypesAnalyzer), TEST_SEARCH_STATS); - // EsqlProject[[s{r}#4]] - var project = as(plan, EsqlProject.class); + // Project[[s{r}#4]] + var project = as(plan, Project.class); assertThat(Expressions.names(project.projections()), contains("s")); // TopN[[Order[s{r}#4,DESC,FIRST]],1[INTEGER]] @@ -1198,8 +1197,8 @@ public boolean isIndexed(FieldAttribute.FieldName field) { } }); - // EsqlProject[[s{r}#4]] - var project = as(plan, EsqlProject.class); + // Project[[s{r}#4]] + var project = as(plan, Project.class); assertThat(Expressions.names(project.projections()), contains("s")); // TopN[[Order[s{r}#4,DESC,FIRST]],1[INTEGER]] @@ -1386,7 +1385,7 @@ public void testAggregateMetricDoubleInlineStats() { LogicalPlan plan = localPlan(plan(query, tsAnalyzer), new EsqlTestUtils.TestSearchStats()); - // EsqlProject[[@timestamp{f}#972, cluster{f}#973, pod{f}#974, network.eth0.tx{f}#991, tx_max{r}#962]] + // Project[[@timestamp{f}#972, cluster{f}#973, pod{f}#974, network.eth0.tx{f}#991, tx_max{r}#962]] var project = as(plan, Project.class); assertThat(Expressions.names(project.projections()), contains("@timestamp", "cluster", "pod", "network.eth0.tx", "tx_max")); // TopN[[Order[@timestamp{f}#972,ASC,LAST], Order[cluster{f}#973,ASC,LAST], Order[pod{f}#974,ASC,LAST]],9[INTEGER],false] @@ -1469,8 +1468,8 @@ public void testVectorFunctionsInWhere() { LogicalPlan plan = localPlan(plan(query, allTypesAnalyzer), TEST_SEARCH_STATS); - // EsqlProject[[dense_vector{f}#25]] - var project = as(plan, EsqlProject.class); + // Project[[dense_vector{f}#25]] + var project = as(plan, Project.class); assertThat(Expressions.names(project.projections()), contains("dense_vector")); var limit = as(project.child(), Limit.class); @@ -1557,8 +1556,8 @@ public void testVectorFunctionsUpdateIntermediateProjections() { LogicalPlan plan = localPlan(plan(query, allTypesAnalyzer), TEST_SEARCH_STATS); - // EsqlProject with all fields including similarity and keyword - var project = as(plan, EsqlProject.class); + // Project with all fields including similarity and keyword + var project = as(plan, Project.class); assertTrue(Expressions.names(project.projections()).contains("similarity")); assertTrue(Expressions.names(project.projections()).contains("keyword")); @@ -1582,8 +1581,8 @@ public void testVectorFunctionsUpdateIntermediateProjections() { var mvExpand = as(eval.child(), MvExpand.class); assertThat(Expressions.name(mvExpand.target()), equalTo("keyword")); - // Inner EsqlProject with the pushed down function - var innerProject = as(mvExpand.child(), EsqlProject.class); + // Inner Project with the pushed down function + var innerProject = as(mvExpand.child(), Project.class); assertTrue(Expressions.names(innerProject.projections()).contains("keyword")); assertTrue( innerProject.projections() @@ -1624,8 +1623,8 @@ public void testVectorFunctionsWithDuplicateFunctions() { LogicalPlan plan = localPlan(plan(query, allTypesAnalyzer), TEST_SEARCH_STATS); - // EsqlProject[[s1{r}#5, s2{r}#8, r2{r}#14]] - var project = as(plan, EsqlProject.class); + // Project[[s1{r}#5, s2{r}#8, r2{r}#14]] + var project = as(plan, Project.class); assertThat(Expressions.names(project.projections()), contains("s1", "s2", "r2")); // Eval with s1, s2, r2 @@ -1736,7 +1735,7 @@ public void testLengthInEval() { """; LogicalPlan plan = localPlan(plan(query, analyzer), TEST_SEARCH_STATS); - var project = as(plan, EsqlProject.class); + var project = as(plan, Project.class); assertThat(Expressions.names(project.projections()), contains("l")); var eval = as(project.child(), Eval.class); Attribute lAttr = assertLengthPushdown(as(eval.fields().getFirst(), Alias.class).child(), "last_name"); @@ -1752,7 +1751,7 @@ public void testLengthInWhere() { """; LogicalPlan plan = localPlan(plan(query, analyzer), TEST_SEARCH_STATS); - var project = as(plan, EsqlProject.class); + var project = as(plan, Project.class); var limit = as(project.child(), Limit.class); var filter = as(limit.child(), Filter.class); Attribute lAttr = assertLengthPushdown(as(filter.condition(), GreaterThan.class).left(), "last_name"); @@ -1788,7 +1787,7 @@ public void testLengthInEvalAfterManyRenames() { """; LogicalPlan plan = localPlan(plan(query, analyzer), TEST_SEARCH_STATS); - var project = as(plan, EsqlProject.class); + var project = as(plan, Project.class); assertThat(Expressions.names(project.projections()), contains("l")); var eval = as(project.child(), Eval.class); Attribute lAttr = assertLengthPushdown(as(eval.fields().getFirst(), Alias.class).child(), "last_name"); @@ -1805,7 +1804,7 @@ public void testLengthInWhereAndEval() { """; LogicalPlan plan = localPlan(plan(query, analyzer), TEST_SEARCH_STATS); - var project = as(plan, EsqlProject.class); + var project = as(plan, Project.class); var eval = as(project.child(), Eval.class); Attribute lAttr = assertLengthPushdown(as(eval.fields().getFirst(), Alias.class).child(), "last_name"); var limit = as(eval.child(), Limit.class); @@ -2053,8 +2052,8 @@ public void testReductionPlanForTopNWithPushedDownFunctions() { var logicalPlan = localPlan(plan(query, allTypesAnalyzer), TEST_SEARCH_STATS); // Verify the logical plan structure: - // EsqlProject[[text{f}#1105, score{r}#1085]] - var project = as(logicalPlan, EsqlProject.class); + // Project[[text{f}#1105, score{r}#1085]] + var project = as(logicalPlan, Project.class); assertThat(Expressions.names(project.projections()), contains("text", "score")); // TopN[[Order[integer{f}#1099,DESC,FIRST]],10[INTEGER],false] @@ -2187,7 +2186,7 @@ public void testPushableFunctionsInFork() { assertTrue(relation1.output().contains(sFieldAttr)); // Second branch: (eval t = v_dot_product(dense_vector, [1, 2, 3]) | keep t, u, keyword) - // EsqlProject[[s{r}#55, _fork{r}#4, t{r}#11]] + // Project[[s{r}#55, _fork{r}#4, t{r}#11]] var project2 = as(fork.children().get(1), Project.class); assertThat(Expressions.names(project2.projections()), containsInAnyOrder("s", "_fork", "t", "u", "keyword")); @@ -2232,8 +2231,8 @@ public void testPushableFunctionsInSubqueries() { """; var localPlan = localPlan(plan(query, allTypesAnalyzer), TEST_SEARCH_STATS); - // EsqlProject[[s{r}#97, t{r}#9]] - var project = as(localPlan, EsqlProject.class); + // Project[[s{r}#97, t{r}#9]] + var project = as(localPlan, Project.class); assertThat(Expressions.names(project.projections()), contains("s", "t")); // Eval[[DOTPRODUCT(dense_vector{r}#82,[1.0, 2.0, 3.0][DENSE_VECTOR]) AS t#9]] @@ -2256,14 +2255,14 @@ public void testPushableFunctionsInSubqueries() { assertThat(unionAll.children(), hasSize(2)); // Second branch of UnionAll - contains the subquery - // EsqlProject[[alias_integer{r}#99, boolean{r}#56, ...]] - var project2 = as(unionAll.children().get(1), EsqlProject.class); + // Project[[alias_integer{r}#99, boolean{r}#56, ...]] + var project2 = as(unionAll.children().get(1), Project.class); // Eval[[null[KEYWORD] AS alias_integer#55, null[BOOLEAN] AS boolean#56, ...]] var eval2 = as(project2.child(), Eval.class); var subquery = as(eval2.child(), Subquery.class); - var subqueryProject = as(subquery.child(), EsqlProject.class); + var subqueryProject = as(subquery.child(), Project.class); assertThat(Expressions.names(subqueryProject.projections()), contains("s")); var subqueryEval = as(subqueryProject.child(), Eval.class); assertThat(subqueryEval.fields(), hasSize(1)); diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/LogicalPlanOptimizerTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/LogicalPlanOptimizerTests.java index e9b8eeb59419a..1fd1924140dc2 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/LogicalPlanOptimizerTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/LogicalPlanOptimizerTests.java @@ -150,7 +150,6 @@ import org.elasticsearch.xpack.esql.plan.logical.join.LookupJoin; import org.elasticsearch.xpack.esql.plan.logical.join.StubRelation; import org.elasticsearch.xpack.esql.plan.logical.local.EmptyLocalSupplier; -import org.elasticsearch.xpack.esql.plan.logical.local.EsqlProject; import org.elasticsearch.xpack.esql.plan.logical.local.LocalRelation; import org.elasticsearch.xpack.esql.plan.logical.local.LocalSupplier; import org.elasticsearch.xpack.esql.rule.RuleExecutor; @@ -270,7 +269,7 @@ public void testEmptyProjections() { | drop salary """); - var project = as(plan, EsqlProject.class); + var project = as(plan, Project.class); assertThat(project.expressions(), is(empty())); var limit = as(project.child(), Limit.class); as(limit.child(), EsRelation.class); @@ -294,7 +293,7 @@ public void testEmptyProjectionInStat() { * Expects * *

{@code
-     * EsqlProject[[x{r}#6]]
+     * Project[[x{r}#6]]
      * \_Eval[[1[INTEGER] AS x]]
      *   \_Limit[1000[INTEGER]]
      *     \_LocalRelation[[{e}#18],[ConstantNullBlock[positions=1]]]
@@ -327,7 +326,7 @@ public void testEmptyProjectInStatWithEval() {
     /**
      * Expects
      * 
{@code
-     * EsqlProject[[x{r}#8]]
+     * Project[[x{r}#8]]
      * \_Eval[[1[INTEGER] AS x]]
      *   \_Limit[1000[INTEGER]]
      *     \_Aggregate[[emp_no{f}#15],[emp_no{f}#15]]
@@ -1033,7 +1032,7 @@ public void testCombineProjectionWithAggregationFirstAndAliasedGroupingUnused()
     /**
      * Expects
      * 
{@code
-     * EsqlProject[[x{r}#3, y{r}#6]]
+     * Project[[x{r}#3, y{r}#6]]
      * \_Eval[[emp_no{f}#9 + 2[INTEGER] AS x, salary{f}#14 + 3[INTEGER] AS y]]
      *   \_Limit[10000[INTEGER]]
      *     \_EsRelation[test][_meta_field{f}#15, emp_no{f}#9, first_name{f}#10, g..]
@@ -1615,7 +1614,7 @@ public void testDontCombineOrderByThroughMvExpand() {
      * 
{@code
      * Limit[1000[INTEGER],true]
      * \_MvExpand[x{r}#4,x{r}#19]
-     *   \_EsqlProject[[first_name{f}#9 AS x]]
+     *   \_Project[[first_name{f}#9 AS x]]
      *     \_Limit[1000[INTEGER],false]
      *       \_EsRelation[test][_meta_field{f}#14, emp_no{f}#8, first_name{f}#9, ge..]
      * }
@@ -1630,7 +1629,7 @@ public void testCopyDefaultLimitPastMvExpand() { var limit = asLimit(plan, 1000, true); var mvExpand = as(limit.child(), MvExpand.class); - var keep = as(mvExpand.child(), EsqlProject.class); + var keep = as(mvExpand.child(), Project.class); var limitPastMvExpand = asLimit(keep.child(), 1000, false); as(limitPastMvExpand.child(), EsRelation.class); } @@ -1666,7 +1665,7 @@ public void testCopyDefaultLimitPastLookupJoin() { *
{@code
      * Limit[10[INTEGER],true]
      * \_MvExpand[first_name{f}#7,first_name{r}#17]
-     *   \_EsqlProject[[first_name{f}#7, last_name{f}#10]]
+     *   \_Project[[first_name{f}#7, last_name{f}#10]]
      *     \_Limit[1[INTEGER],false]
      *       \_EsRelation[test][_meta_field{f}#12, emp_no{f}#6, first_name{f}#7, ge..]
      * }
@@ -1682,7 +1681,7 @@ public void testDontPushDownLimitPastMvExpand() { var limit = asLimit(plan, 10, true); var mvExpand = as(limit.child(), MvExpand.class); - var project = as(mvExpand.child(), EsqlProject.class); + var project = as(mvExpand.child(), Project.class); var limit2 = asLimit(project.child(), 1, false); as(limit2.child(), EsRelation.class); } @@ -1718,7 +1717,7 @@ public void testDontPushDownLimitPastLookupJoin() { /** * Expected *
{@code
-     * EsqlProject[[emp_no{f}#19, first_name{r}#30, languages{f}#22, lll{r}#9, salary{r}#31]]
+     * Project[[emp_no{f}#19, first_name{r}#30, languages{f}#22, lll{r}#9, salary{r}#31]]
      * \_TopN[[Order[salary{r}#31,DESC,FIRST]],5[INTEGER]]
      *   \_Limit[5[INTEGER],true]
      *     \_MvExpand[salary{f}#24,salary{r}#31]
@@ -1748,7 +1747,7 @@ public void testMultipleMvExpandWithSortAndLimit() {
             | sort salary desc
             """);
 
-        var keep = as(plan, EsqlProject.class);
+        var keep = as(plan, Project.class);
         var topN = as(keep.child(), TopN.class);
         assertThat(topN.limit().fold(FoldContext.small()), equalTo(5));
         assertThat(orderNames(topN), contains("salary"));
@@ -1823,7 +1822,7 @@ public void testMultipleLookupJoinWithSortAndLimit() {
 
     /**
      * 
{@code
-     * EsqlProject[[emp_no{f}#10, first_name{r}#21, salary{f}#15]]
+     * Project[[emp_no{f}#10, first_name{r}#21, salary{f}#15]]
      * \_TopN[[Order[salary{f}#15,ASC,LAST], Order[first_name{r}#21,ASC,LAST]],5[INTEGER]]
      *   \_MvExpand[first_name{f}#11,first_name{r}#21,null]
      *     \_EsRelation[test][_meta_field{f}#16, emp_no{f}#10, first_name{f}#11, ..]
@@ -1838,7 +1837,7 @@ public void testPushDownLimitThroughMultipleSort_AfterMvExpand() {
             | sort salary, first_name
             | limit 5""");
 
-        var keep = as(plan, EsqlProject.class);
+        var keep = as(plan, Project.class);
         var topN = as(keep.child(), TopN.class);
         assertThat(topN.limit().fold(FoldContext.small()), equalTo(5));
         assertThat(orderNames(topN), contains("salary", "first_name"));
@@ -1849,7 +1848,7 @@ public void testPushDownLimitThroughMultipleSort_AfterMvExpand() {
     /**
      * Expected
      * 
{@code
-     * EsqlProject[[emp_no{f}#2560, first_name{r}#2571, salary{f}#2565]]
+     * Project[[emp_no{f}#2560, first_name{r}#2571, salary{f}#2565]]
      * \_TopN[[Order[first_name{r}#2571,ASC,LAST]],5[INTEGER]]
      *   \_TopN[[Order[salary{f}#2565,ASC,LAST]],5[INTEGER]]
      *     \_MvExpand[first_name{f}#2561,first_name{r}#2571,null]
@@ -1866,7 +1865,7 @@ public void testPushDownLimitThroughMultipleSort_AfterMvExpand2() {
             | limit 5
             | sort first_name""");
 
-        var keep = as(plan, EsqlProject.class);
+        var keep = as(plan, Project.class);
         var topN = as(keep.child(), TopN.class);
         assertThat(topN.limit().fold(FoldContext.small()), equalTo(5));
         assertThat(orderNames(topN), contains("first_name"));
@@ -1983,7 +1982,7 @@ public void testPushDown_TheRightLimit_PastLookupJoin() {
     /**
      * Expected
      * 
{@code
-     * EsqlProject[[first_name{f}#11, emp_no{f}#10, salary{f}#12, b{r}#4]]
+     * Project[[first_name{f}#11, emp_no{f}#10, salary{f}#12, b{r}#4]]
      *  \_TopN[[Order[salary{f}#12,ASC,LAST]],5[INTEGER]]
      *    \_Eval[[100[INTEGER] AS b]]
      *      \_MvExpand[first_name{f}#11]
@@ -2000,7 +1999,7 @@ public void testPushDownLimit_PastEvalAndMvExpand() {
             | limit 5
             | keep first_name, emp_no, salary, b""");
 
-        var keep = as(plan, EsqlProject.class);
+        var keep = as(plan, Project.class);
         var topN = as(keep.child(), TopN.class);
         assertThat(topN.limit().fold(FoldContext.small()), equalTo(5));
         assertThat(orderNames(topN), contains("salary"));
@@ -2012,7 +2011,7 @@ public void testPushDownLimit_PastEvalAndMvExpand() {
     /**
      * Expected
      * 
{@code
-     * EsqlProject[[emp_no{f}#5885, first_name{r}#5896, salary{f}#5890]]
+     * Project[[emp_no{f}#5885, first_name{r}#5896, salary{f}#5890]]
      * \_TopN[[Order[salary{f}#5890,ASC,LAST], Order[first_name{r}#5896,ASC,LAST]],1000[INTEGER]]
      *   \_Filter[gender{f}#5887 == [46][KEYWORD] AND WILDCARDLIKE(first_name{r}#5896)]
      *     \_MvExpand[first_name{f}#5886,first_name{r}#5896,null]
@@ -2029,7 +2028,7 @@ public void testRedundantSort_BeforeMvExpand_WithFilterOnExpandedField_ResultTru
             | keep emp_no, first_name, salary
             | sort salary, first_name""");
 
-        var keep = as(plan, EsqlProject.class);
+        var keep = as(plan, Project.class);
         var topN = as(keep.child(), TopN.class);
         assertThat(topN.limit().fold(FoldContext.small()), equalTo(1000));
         assertThat(orderNames(topN), contains("salary", "first_name"));
@@ -2135,7 +2134,7 @@ public void testMultiMvExpand_SortDownBelow() {
      * 
{@code
      * Limit[10000[INTEGER],true]
      * \_MvExpand[c{r}#7,c{r}#16]
-     *   \_EsqlProject[[c{r}#7, a{r}#3]]
+     *   \_Project[[c{r}#7, a{r}#3]]
      *     \_TopN[[Order[a{r}#3,ASC,FIRST]],7300[INTEGER]]
      *       \_Limit[7300[INTEGER],true]
      *         \_MvExpand[b{r}#5,b{r}#15]
@@ -2156,7 +2155,7 @@ public void testLimitThenSortBeforeMvExpand() {
 
         var limit10kBefore = asLimit(plan, 10000, true);
         var mvExpand = as(limit10kBefore.child(), MvExpand.class);
-        var project = as(mvExpand.child(), EsqlProject.class);
+        var project = as(mvExpand.child(), Project.class);
         var topN = as(project.child(), TopN.class);
         assertThat(topN.limit().fold(FoldContext.small()), equalTo(7300));
         assertThat(orderNames(topN), contains("a"));
@@ -2233,7 +2232,7 @@ public void testRemoveUnusedSortBeforeMvExpand_DefaultLimit10000() {
     /**
      * Expected
      * 
{@code
-     * EsqlProject[[emp_no{f}#3517, first_name{r}#3528, salary{f}#3522]]
+     * Project[[emp_no{f}#3517, first_name{r}#3528, salary{f}#3522]]
      * \_TopN[[Order[salary{f}#3522,ASC,LAST], Order[first_name{r}#3528,ASC,LAST]],15[INTEGER]]
      *   \_Filter[gender{f}#3519 == [46][KEYWORD] AND WILDCARDLIKE(first_name{r}#3528)]
      *     \_MvExpand[first_name{f}#3518,first_name{r}#3528,null]
@@ -2251,7 +2250,7 @@ public void testRedundantSort_BeforeMvExpand_WithFilterOnExpandedField() {
             | sort salary, first_name
             | limit 15""");
 
-        var keep = as(plan, EsqlProject.class);
+        var keep = as(plan, Project.class);
         var topN = as(keep.child(), TopN.class);
         assertThat(topN.limit().fold(FoldContext.small()), equalTo(15));
         assertThat(orderNames(topN), contains("salary", "first_name"));
@@ -2264,7 +2263,7 @@ public void testRedundantSort_BeforeMvExpand_WithFilterOnExpandedField() {
     /**
      * Expected
      * 
{@code
-     * EsqlProject[[emp_no{f}#3421, first_name{r}#3432, salary{f}#3426]]
+     * Project[[emp_no{f}#3421, first_name{r}#3432, salary{f}#3426]]
      * \_TopN[[Order[salary{f}#3426,ASC,LAST], Order[first_name{r}#3432,ASC,LAST]],15[INTEGER]]
      *   \_Filter[gender{f}#3423 == [46][KEYWORD] AND salary{f}#3426 > 60000[INTEGER]]
      *     \_MvExpand[first_name{f}#3422,first_name{r}#3432,null]
@@ -2282,7 +2281,7 @@ public void testRedundantSort_BeforeMvExpand_WithFilter_NOT_OnExpandedField() {
             | sort salary, first_name
             | limit 15""");
 
-        var keep = as(plan, EsqlProject.class);
+        var keep = as(plan, Project.class);
         var topN = as(keep.child(), TopN.class);
         assertThat(topN.limit().fold(FoldContext.small()), equalTo(15));
         assertThat(orderNames(topN), contains("salary", "first_name"));
@@ -2295,7 +2294,7 @@ public void testRedundantSort_BeforeMvExpand_WithFilter_NOT_OnExpandedField() {
     /**
      * Expected
      * 
{@code
-     * EsqlProject[[emp_no{f}#2085, first_name{r}#2096 AS x, salary{f}#2090]]
+     * Project[[emp_no{f}#2085, first_name{r}#2096 AS x, salary{f}#2090]]
      * \_TopN[[Order[salary{f}#2090,ASC,LAST], Order[first_name{r}#2096,ASC,LAST]],15[INTEGER]]
      *   \_Filter[gender{f}#2087 == [46][KEYWORD] AND WILDCARDLIKE(first_name{r}#2096)]
      *     \_MvExpand[first_name{f}#2086,first_name{r}#2096,null]
@@ -2529,7 +2528,7 @@ public void testDescendantLimitLookupJoin() {
 
     /**
      * 
{@code
-     * EsqlProject[[emp_no{f}#9, first_name{f}#10, languages{f}#12, language_code{r}#3, language_name{r}#22]]
+     * Project[[emp_no{f}#9, first_name{f}#10, languages{f}#12, language_code{r}#3, language_name{r}#22]]
      * \_Eval[[null[INTEGER] AS language_code#3, null[KEYWORD] AS language_name#22]]
      *   \_Limit[1000[INTEGER],false]
      *     \_EsRelation[test][_meta_field{f}#15, emp_no{f}#9, first_name{f}#10, g..]
@@ -3150,7 +3149,7 @@ public void testEnrichNotNullFilter() {
     /**
      * Expects
      * 
{@code
-     * EsqlProject[[a{r}#3, last_name{f}#9]]
+     * Project[[a{r}#3, last_name{f}#9]]
      * \_Eval[[__a_SUM_123{r}#12 / __a_COUNT_150{r}#13 AS a]]
      *   \_Limit[10000[INTEGER]]
      *     \_Aggregate[[last_name{f}#9],[SUM(salary{f}#10) AS __a_SUM_123, COUNT(salary{f}#10) AS __a_COUNT_150, last_nam
@@ -3187,7 +3186,7 @@ public void testSimpleAvgReplacement() {
     /**
      * Expects
      * 
{@code
-     * EsqlProject[[a{r}#3, c{r}#6, s{r}#9, last_name{f}#15]]
+     * Project[[a{r}#3, c{r}#6, s{r}#9, last_name{f}#15]]
      * \_Eval[[s{r}#9 / c{r}#6 AS a]]
      *   \_Limit[10000[INTEGER]]
      *     \_Aggregate[[last_name{f}#15],[COUNT(salary{f}#16) AS c, SUM(salary{f}#16) AS s, last_name{f}#15]]
@@ -3215,7 +3214,7 @@ public void testClashingAggAvgReplacement() {
     /**
      * Expects
      * 
{@code
-     * EsqlProject[[a{r}#3, c{r}#6, s{r}#9, last_name{f}#15]]
+     * Project[[a{r}#3, c{r}#6, s{r}#9, last_name{f}#15]]
      * \_Eval[[s{r}#9 / __a_COUNT@xxx{r}#18 AS a]]
      *   \_Limit[10000[INTEGER]]
      *     \_Aggregate[[last_name{f}#15],[COUNT(salary{f}#16) AS __a_COUNT@xxx, COUNT(languages{f}#14) AS c, SUM(salary{f}#16) AS
@@ -4743,7 +4742,7 @@ public void testStatsWithCanonicalAggregate() throws Exception {
      *
      * 
{@code
      * Limit[1000[INTEGER]]
-     * \_EsqlProject[[s{r}#3, s_expr{r}#5, s_null{r}#7, w{r}#10]]
+     * \_Project[[s{r}#3, s_expr{r}#5, s_null{r}#7, w{r}#10]]
      *   \_Project[[s{r}#3, s_expr{r}#5, s_null{r}#7, w{r}#10]]
      *     \_Eval[[COALESCE(MVCOUNT([1, 2][INTEGER]),0[INTEGER]) * $$COUNT$s$0{r}#26 AS s, COALESCE(MVCOUNT(314.0[DOUBLE] / 100[
      * INTEGER]),0[INTEGER]) * $$COUNT$s$0{r}#26 AS s_expr, COALESCE(MVCOUNT(null[NULL]),0[INTEGER]) * $$COUNT$s$0{r}#26 AS s_null]]
@@ -4763,8 +4762,8 @@ public void testCountOfLiteral() {
             """, new TestSubstitutionOnlyOptimizer());
 
         var limit = as(plan, Limit.class);
-        var esqlProject = as(limit.child(), EsqlProject.class);
-        var project = as(esqlProject.child(), Project.class);
+        var topProject = as(limit.child(), Project.class);
+        var project = as(topProject.child(), Project.class);
         var eval = as(project.child(), Eval.class);
         var agg = as(eval.child(), Aggregate.class);
 
@@ -4815,7 +4814,7 @@ public void testCountOfLiteral() {
      *
      * 
{@code
      * Limit[1000[INTEGER]]
-     * \_EsqlProject[[s{r}#3, s_expr{r}#5, s_null{r}#7, w{r}#10]]
+     * \_Project[[s{r}#3, s_expr{r}#5, s_null{r}#7, w{r}#10]]
      *   \_Project[[s{r}#3, s_expr{r}#5, s_null{r}#7, w{r}#10]]
      *     \_Eval[[MVSUM([1, 2][INTEGER]) * $$COUNT$s$0{r}#25 AS s, MVSUM(314.0[DOUBLE] / 100[INTEGER]) * $$COUNT$s$0{r}#25 AS s
      * _expr, MVSUM(null[NULL]) * $$COUNT$s$0{r}#25 AS s_null]]
@@ -4835,8 +4834,8 @@ public void testSumOfLiteral() {
             """, new TestSubstitutionOnlyOptimizer());
 
         var limit = as(plan, Limit.class);
-        var esqlProject = as(limit.child(), EsqlProject.class);
-        var project = as(esqlProject.child(), Project.class);
+        var topProject = as(limit.child(), Project.class);
+        var project = as(topProject.child(), Project.class);
         var eval = as(project.child(), Eval.class);
         var agg = as(eval.child(), Aggregate.class);
 
@@ -4915,7 +4914,7 @@ private record AggOfLiteralTestCase(
      *
      * 
{@code
      * Limit[1000[INTEGER]]
-     * \_EsqlProject[[s{r}#3, s_expr{r}#5, s_null{r}#7]]
+     * \_Project[[s{r}#3, s_expr{r}#5, s_null{r}#7]]
      *   \_Project[[s{r}#3, s_expr{r}#5, s_null{r}#7]]
      *     \_Eval[[MVAVG([1, 2][INTEGER]) AS s, MVAVG(314.0[DOUBLE] / 100[INTEGER]) AS s_expr, MVAVG(null[NULL]) AS s_null]]
      *       \_LocalRelation[[{e}#21],[ConstantNullBlock[positions=1]]]
@@ -4942,8 +4941,8 @@ public void testAggOfLiteral() {
             var plan = plan(query, new TestSubstitutionOnlyOptimizer());
 
             var limit = as(plan, Limit.class);
-            var esqlProject = as(limit.child(), EsqlProject.class);
-            var project = as(esqlProject.child(), Project.class);
+            var topProject = as(limit.child(), Project.class);
+            var project = as(topProject.child(), Project.class);
             var eval = as(project.child(), Eval.class);
             var singleRowRelation = as(eval.child(), LocalRelation.class);
             var singleRow = singleRowRelation.supplier().get();
@@ -4961,7 +4960,7 @@ public void testAggOfLiteral() {
      *
      * 
{@code
      * Limit[1000[INTEGER]]
-     * \_EsqlProject[[s{r}#3, s_expr{r}#5, s_null{r}#7, emp_no{f}#13]]
+     * \_Project[[s{r}#3, s_expr{r}#5, s_null{r}#7, emp_no{f}#13]]
      *   \_Project[[s{r}#3, s_expr{r}#5, s_null{r}#7, emp_no{f}#13]]
      *     \_Eval[[MVAVG([1, 2][INTEGER]) AS s, MVAVG(314.0[DOUBLE] / 100[INTEGER]) AS s_expr, MVAVG(null[NULL]) AS s_null]]
      *       \_Aggregate[[emp_no{f}#13],[emp_no{f}#13]]
@@ -4990,8 +4989,8 @@ public void testAggOfLiteralGrouped() {
             var plan = plan(query, new TestSubstitutionOnlyOptimizer());
 
             var limit = as(plan, Limit.class);
-            var esqlProject = as(limit.child(), EsqlProject.class);
-            var project = as(esqlProject.child(), Project.class);
+            var topProject = as(limit.child(), Project.class);
+            var project = as(topProject.child(), Project.class);
             var eval = as(project.child(), Eval.class);
             var agg = as(eval.child(), Aggregate.class);
             assertThat(agg.child(), instanceOf(EsRelation.class));
@@ -5740,7 +5739,7 @@ public void testInlinestatsGetsPrunedEntirely() {
     }
 
     /*
-     * EsqlProject[[emp_no{f}#16, count{r}#7]]
+     * Project[[emp_no{f}#16, count{r}#7]]
      * \_TopN[[Order[emp_no{f}#16,ASC,LAST]],5[INTEGER]]
      *   \_InlineJoin[LEFT,[salaryK{r}#5],[salaryK{r}#5],[salaryK{r}#5]]
      *     |_Eval[[salary{f}#21 / 1000[INTEGER] AS salaryK#5]]
@@ -5880,10 +5879,10 @@ public void testTripleInlineStatsGetsPrunedPartially() {
     }
 
     /*
-     * EsqlProject[[emp_no{f}#26, salaryK{r}#4, count{r}#6, min{r}#19]]
+     * Project[[emp_no{f}#26, salaryK{r}#4, count{r}#6, min{r}#19]]
      * \_TopN[[Order[emp_no{f}#26,ASC,LAST]],5[INTEGER]]
      *   \_InlineJoin[LEFT,[salaryK{r}#4],[salaryK{r}#4]]
-     *     |_EsqlProject[[_meta_field{f}#32, emp_no{f}#26, first_name{f}#27, gender{f}#28, hire_date{f}#33, job{f}#34, job.raw{f}#35,
+     *     |_Project[[_meta_field{f}#32, emp_no{f}#26, first_name{f}#27, gender{f}#28, hire_date{f}#33, job{f}#34, job.raw{f}#35,
      *              languages{f}#29, last_name{f}#30, long_noidx{f}#36, salary{f}#31, count{r}#6, salaryK{r}#4, hire_date_string{r}#10,
      *              date{r}#15]]
      *     | \_Dissect[hire_date_string{r}#10,Parser[pattern=%{date}, appendSeparator=,
@@ -5964,7 +5963,7 @@ public void testTripleInlineStatsMultipleAssignmentsGetsPrunedPartially() {
     }
 
     /*
-     * EsqlProject[[emp_no{f}#917]]
+     * Project[[emp_no{f}#917]]
      * \_TopN[[Order[emp_no{f}#917,ASC,LAST]],5[INTEGER]]
      *   \_Dissect[hire_date_string{r}#898,Parser[pattern=%{date}, appendSeparator=,
      *          parser=org.elasticsearch.dissect.DissectParser@46132aa7],[date{r}#903]] <-- TODO: Dissect & Eval could/should be dropped
@@ -6083,7 +6082,7 @@ public void testInlineStatsWithAggGetsPrunedEntirely() {
     }
 
     /*
-     * EsqlProject[[avg{r}#1053, decades{r}#1049, avgavg{r}#1063]]
+     * Project[[avg{r}#1053, decades{r}#1049, avgavg{r}#1063]]
      * \_Limit[1000[INTEGER],true]
      *   \_InlineJoin[LEFT,[],[],[]]
      *     |_Project[[avg{r}#1053, decades{r}#1049, idecades{r}#1056]]
@@ -6116,7 +6115,7 @@ public void testInlineStatsWithAggAndInlineStatsGetsPruned() {
         }
         var plan = optimizedPlan(query);
 
-        var project = as(plan, EsqlProject.class);
+        var project = as(plan, Project.class);
         assertThat(Expressions.names(project.projections()), is(List.of("avg", "decades", "avgavg")));
         var limit = asLimit(project.child(), 1000, false);
         var inlineJoin = as(limit.child(), InlineJoin.class);
@@ -6182,7 +6181,7 @@ public void testInlineStatsWithLookupJoin() {
     }
 
     /*
-     * EsqlProject[[avg{r}#4, emp_no{f}#9, first_name{f}#10]]
+     * Project[[avg{r}#4, emp_no{f}#9, first_name{f}#10]]
      * \_Limit[10[INTEGER],false]
      *   \_InlineJoin[LEFT,[emp_no{f}#9],[emp_no{f}#9],[emp_no{r}#9]]
      *     |_EsRelation[test][_meta_field{f}#15, emp_no{f}#9, first_name{f}#10, g..]
@@ -6205,15 +6204,15 @@ public void testInlineStatsWithAvg() {
         }
         var plan = optimizedPlan(query);
 
-        var esqlProject = as(plan, EsqlProject.class);
-        assertThat(Expressions.names(esqlProject.projections()), is(List.of("avg", "emp_no", "first_name")));
-        var upperLimit = asLimit(esqlProject.child(), 10, false);
+        var project = as(plan, Project.class);
+        assertThat(Expressions.names(project.projections()), is(List.of("avg", "emp_no", "first_name")));
+        var upperLimit = asLimit(project.child(), 10, false);
         var inlineJoin = as(upperLimit.child(), InlineJoin.class);
         assertThat(Expressions.names(inlineJoin.config().leftFields()), is(List.of("emp_no")));
         // Left
         var relation = as(inlineJoin.left(), EsRelation.class);
         // Right
-        var project = as(inlineJoin.right(), Project.class);
+        project = as(inlineJoin.right(), Project.class);
         assertThat(Expressions.names(project.projections()), contains("avg", "emp_no"));
         var eval = as(project.child(), Eval.class);
         assertThat(Expressions.names(eval.fields()), is(List.of("avg")));
@@ -6223,7 +6222,7 @@ public void testInlineStatsWithAvg() {
     }
 
     /*
-     * EsqlProject[[emp_no{r}#5]]
+     * Project[[emp_no{r}#5]]
      * \_Limit[1000[INTEGER],false]
      *   \_LocalRelation[[salary{r}#3, emp_no{r}#5, gender{r}#7],
      *      org.elasticsearch.xpack.esql.plan.logical.local.CopyingLocalSupplier@9d5b596d]
@@ -6240,9 +6239,9 @@ public void testInlineStatsWithRow() {
         }
         var plan = optimizedPlan(query);
 
-        var esqlProject = as(plan, Project.class);
-        assertThat(Expressions.names(esqlProject.projections()), is(List.of("emp_no")));
-        var limit = asLimit(esqlProject.child(), 1000, false);
+        var project = as(plan, Project.class);
+        assertThat(Expressions.names(project.projections()), is(List.of("emp_no")));
+        var limit = asLimit(project.child(), 1000, false);
         var localRelation = as(limit.child(), LocalRelation.class);
         assertThat(
             localRelation.output(),
@@ -6255,7 +6254,7 @@ public void testInlineStatsWithRow() {
     }
 
     /*
-     * EsqlProject[[a{r}#4]]
+     * Project[[a{r}#4]]
      * \_Limit[2[INTEGER],false]
      *   \_InlineJoin[LEFT,[],[],[]]
      *     |_EsRelation[test][_meta_field{f}#12, emp_no{f}#6, first_name{f}#7, ge..]
@@ -6278,7 +6277,7 @@ public void testInlineStatsWithLimit() {
         }
         var plan = optimizedPlan(query);
 
-        var project = as(plan, EsqlProject.class);
+        var project = as(plan, Project.class);
         assertThat(Expressions.names(project.projections()), is(List.of("a")));
         var limit = asLimit(project.child(), 2, false);
         var inlineJoin = as(limit.child(), InlineJoin.class);
@@ -6298,7 +6297,7 @@ public void testInlineStatsWithLimit() {
      * \_Aggregate[[],[VALUES(max_lang{r}#7,true[BOOLEAN]) AS v#11]]
      *   \_Limit[1[INTEGER],false]
      *     \_InlineJoin[LEFT,[gender{f}#14],[gender{f}#14],[gender{r}#14]]
-     *       |_EsqlProject[[emp_no{f}#12, languages{f}#15, gender{f}#14]]
+     *       |_Project[[emp_no{f}#12, languages{f}#15, gender{f}#14]]
      *       | \_EsRelation[test][_meta_field{f}#18, emp_no{f}#12, first_name{f}#13, ..]
      *       \_Aggregate[[gender{f}#14],[MAX(languages{f}#15,true[BOOLEAN]) AS max_lang#7, gender{f}#14]]
      *         \_StubRelation[[emp_no{f}#12, languages{f}#15, gender{f}#14]]
@@ -6322,7 +6321,7 @@ public void testInlineStatsWithLimitAndAgg() {
         var innerLimit = asLimit(aggregate.child(), 1, false);
         var inlineJoin = as(innerLimit.child(), InlineJoin.class);
         // Left
-        var project = as(inlineJoin.left(), EsqlProject.class);
+        var project = as(inlineJoin.left(), Project.class);
         var relation = as(project.child(), EsRelation.class);
         // Right
         var agg = as(inlineJoin.right(), Aggregate.class);
@@ -6330,7 +6329,7 @@ public void testInlineStatsWithLimitAndAgg() {
     }
 
     /*
-     * EsqlProject[[c{r}#7, b{r}#5, a{r}#14]]
+     * Project[[c{r}#7, b{r}#5, a{r}#14]]
      * \_Eval[[[KEYWORD] AS a#14]]
      *   \_Limit[1000[INTEGER],false]
      *     \_LocalRelation[[a{r}#3, b{r}#5, c{r}#7],Page{blocks=[ConstantNullBlock[positions=1], IntVectorBlock[vector=ConstantIntVector[p
@@ -6789,7 +6788,7 @@ protected List filteredWarnings() {
      * Expects
      * 
{@code
      * Join[JoinConfig[type=LEFT OUTER, matchFields=[int{r}#4], conditions=[LOOKUP int_number_names ON int]]]
-     * |_EsqlProject[[_meta_field{f}#12, emp_no{f}#6, first_name{f}#7, gender{f}#8, job{f}#13, job.raw{f}#14, languages{f}#9 AS int
+     * |_Project[[_meta_field{f}#12, emp_no{f}#6, first_name{f}#7, gender{f}#8, job{f}#13, job.raw{f}#14, languages{f}#9 AS int
      * , last_name{f}#10, long_noidx{f}#15, salary{f}#11]]
      * | \_Limit[1000[INTEGER]]
      * |   \_EsRelation[test][_meta_field{f}#12, emp_no{f}#6, first_name{f}#7, ge..]
@@ -6819,7 +6818,7 @@ public void testLookupSimple() {
         );
 
         // Left is the rest of the query
-        var left = as(join.left(), EsqlProject.class);
+        var left = as(join.left(), Project.class);
         assertThat(left.output().toString(), containsString("int{r}"));
         var limit = as(left.child(), Limit.class);
         assertThat(limit.limit().fold(FoldContext.small()), equalTo(1000));
@@ -6870,7 +6869,7 @@ public void testLookupSimple() {
      * Limit[1000[INTEGER]]
      * \_Aggregate[[name{r}#20],[MIN(emp_no{f}#9) AS MIN(emp_no), name{r}#20]]
      *   \_Join[JoinConfig[type=LEFT OUTER, matchFields=[int{r}#4], conditions=[LOOKUP int_number_names ON int]]]
-     *     |_EsqlProject[[_meta_field{f}#15, emp_no{f}#9, first_name{f}#10, gender{f}#11, job{f}#16, job.raw{f}#17, languages{f}#12 AS
+     *     |_Project[[_meta_field{f}#15, emp_no{f}#9, first_name{f}#10, gender{f}#11, job{f}#16, job.raw{f}#17, languages{f}#12 AS
      * int, last_name{f}#13, long_noidx{f}#18, salary{f}#14]]
      *     | \_EsRelation[test][_meta_field{f}#15, emp_no{f}#9, first_name{f}#10, g..]
      *     \_LocalRelation[[int{f}#19, name{f}#20],[IntVectorBlock[vector=IntArrayVector[positions=10, values=[0, 1, 2, 3, 4, 5, 6, 7, 8,
@@ -6909,7 +6908,7 @@ public void testLookupStats() {
         );
 
         // Left is the rest of the query
-        var left = as(join.left(), EsqlProject.class);
+        var left = as(join.left(), Project.class);
         assertThat(left.output().toString(), containsString("int{r}"));
         as(left.child(), EsRelation.class);
 
@@ -7284,7 +7283,7 @@ public void testLookupJoinPushDownDisabledForDisjunctionBetweenLeftAndRightField
      * 

* Expects *

{@code
-     * EsqlProject[[languages{f}#21]]
+     * Project[[languages{f}#21]]
      * \_Limit[1000[INTEGER],true]
      *   \_Join[LEFT,[language_code{r}#4],[language_code{r}#4],[language_code{f}#29]]
      *     |_Project[[_meta_field{f}#24, emp_no{f}#18, first_name{f}#19, gender{f}#20, hire_date{f}#25, job{f}#26, job.raw{f}#27, l
@@ -9565,7 +9564,7 @@ public void LookupJoinSemanticFilterDeupPushdown() {
     }
 
     /**
-     * EsqlProject[[@timestamp{r}#3]]
+     * Project[[@timestamp{r}#3]]
      * \_Eval[[1715300259000[DATETIME] AS @timestamp#3]]
      *   \_Limit[1000[INTEGER],false]
      *     \_EsRelation[k8s][@timestamp{f}#5, client.ip{f}#9, cluster{f}#6, ...]
@@ -9644,7 +9643,7 @@ public void testTranslateTRangeFoldsToLocalRelation() {
 
     /**
      * 
{@code
-     * EsqlProject[[to_long{r}#2754, to_integer{r}#2757]]
+     * Project[[to_long{r}#2754, to_integer{r}#2757]]
      * \_Eval[[TOLONG(string{f}#2761) AS to_long#2754, TOINTEGER(string{f}#2761) AS to_integer#2757]]
      *         ^                                       ^
      *         one argument to_long(value) is rewritten to ToLong
@@ -9680,7 +9679,7 @@ public void testToLongAndToIntegerSurrogateFoldsToLongAndToInteger() {
 
     /**
      * 
{@code
-     * EsqlProject[[to_long{r}#2445, to_integer{r}#2449]]
+     * Project[[to_long{r}#2445, to_integer{r}#2449]]
      * \_Eval[[TOLONGBASE(string{f}#2453,base{f}#2454) AS to_long#2445, TOINTEGERBASE(string{f}#2453,base{f}#2454) AS to_integer#2449]]
      *         ^                                                        ^
      *         two argument to_long(string, base) is rewritten to ToLongBase
@@ -9716,7 +9715,7 @@ public void testToLongAndToIntegerSurrogateFoldsToLongBaseAndToIntegerBase() {
 
     /**
      * 
{@code
-     * EsqlProject[[ubase{r}#1871, to_long{r}#1875, to_integer{r}#1879]]
+     * Project[[ubase{r}#1871, to_long{r}#1875, to_integer{r}#1879]]
      * \_Eval[[TOUNSIGNEDLONG(base{f}#1885) AS ubase#1871,
      *         TOLONGBASE(string{f}#1884,TOINTEGER(ubase{r}#1871)) AS to_long#1875,
      *         TOINTEGERBASE(string{f}#1884,TOINTEGER(ubase{r}#1871)) AS to_integer#1879]]
@@ -9885,7 +9884,7 @@ STATS std_dev(network.eth0.currently_connected_clients)
     }
 
     /**
-     * EsqlProject[[first_name{r}#32]]
+     * Project[[first_name{r}#32]]
      * \_Limit[1000[INTEGER],false,false]
      *   \_Filter[_fork{r}#33 == fork1[KEYWORD]]
      *     \_Fork[[first_name{r}#32, _fork{r}#33]]
@@ -9911,7 +9910,7 @@ public void testPruneColumnsInForkBranchesSimpleEvalOutsideBranches() {
                 | DROP _fork
             """;
         var plan = optimizedPlan(query);
-        var project = as(plan, EsqlProject.class);
+        var project = as(plan, Project.class);
         assertThat(project.projections().size(), equalTo(1));
         assertThat(Expressions.names(project.projections()), contains("first_name"));
         var limit = as(project.child(), Limit.class);
@@ -9933,7 +9932,7 @@ public void testPruneColumnsInForkBranchesSimpleEvalOutsideBranches() {
     }
 
     /**
-     * EsqlProject[[_fork{r}#76, emp_no{r}#62, x{r}#73, y{r}#74, z{r}#75]]
+     * Project[[_fork{r}#76, emp_no{r}#62, x{r}#73, y{r}#74, z{r}#75]]
      * \_TopN[[Order[_fork{r}#76,ASC,LAST], Order[emp_no{r}#62,ASC,LAST]],1000[INTEGER],false]
      *   \_Fork[[emp_no{r}#62, x{r}#73, y{r}#74, z{r}#75, _fork{r}#76]]
      *     |_Project[[emp_no{f}#37, x{r}#15, y{r}#16, z{r}#17, _fork{r}#5]]
@@ -9967,7 +9966,7 @@ public void testPruneColumnsInForkBranchesDropNestedEvalsFromOutputIfNotNeeded()
              | SORT _fork, emp_no
             """;
         var plan = optimizedPlan(query);
-        var project = as(plan, EsqlProject.class);
+        var project = as(plan, Project.class);
         assertThat(project.projections().size(), equalTo(5));
         assertThat(Expressions.names(project.projections()), containsInAnyOrder("_fork", "emp_no", "x", "y", "z"));
         var topN = as(project.child(), TopN.class);
@@ -10108,7 +10107,7 @@ public void testPruneColumnsInForkBranchesPruneIfAggregation() {
     }
 
     /**
-     * EsqlProject[[languages{r}#33]]
+     * Project[[languages{r}#33]]
      * \_Limit[10000[INTEGER],false,false]
      *   \_Filter[_fork{r}#34 == fork1[KEYWORD]]
      *     \_Fork[[languages{r}#33, _fork{r}#34]]
@@ -10135,7 +10134,7 @@ public void testPruneColumnsInForkBranchesShouldRespectOuterAlias() {
             | drop _fork
             """;
         var plan = optimizedPlan(query);
-        var project = as(plan, EsqlProject.class);
+        var project = as(plan, Project.class);
         assertThat(project.projections().size(), equalTo(1));
         assertThat(Expressions.names(project.projections()), contains("languages"));
         var limit = as(project.child(), Limit.class);
@@ -10161,7 +10160,7 @@ public void testPruneColumnsInForkBranchesShouldRespectOuterAlias() {
     }
 
     /**
-     * EsqlProject[[languages{r}#55]]
+     * Project[[languages{r}#55]]
      * \_Limit[1000[INTEGER],false,false]
      *   \_Filter[_fork{r}#57 == fork1[KEYWORD]]
      *     \_Fork[[languages{r}#55, _fork{r}#57]]
@@ -10186,7 +10185,7 @@ public void testPruneColumnsInForkBranchesShouldKeepAliasWithSameNameAsColumn()
             | keep languages
             """;
         var plan = optimizedPlan(query);
-        var project = as(plan, EsqlProject.class);
+        var project = as(plan, Project.class);
         assertThat(project.projections().size(), equalTo(1));
         assertThat(Expressions.names(project.projections()), contains("languages"));
         var limit = as(project.child(), Limit.class);
@@ -10228,7 +10227,7 @@ public void testPruneColumnsInForkBranchesShouldKeepAliasWithSameNameAsColumn()
     }
 
     /**
-     * EsqlProject[[_meta_field{r}#48, emp_no{r}#49, first_name{r}#50, gender{r}#51, hire_date{r}#52, job{r}#53, job.raw{r}#54, l
+     * Project[[_meta_field{r}#48, emp_no{r}#49, first_name{r}#50, gender{r}#51, hire_date{r}#52, job{r}#53, job.raw{r}#54, l
      * ast_name{r}#55, long_noidx{r}#56, salary{r}#57]]
      * \_Limit[1000[INTEGER],false,false]
      *   \_Filter[_fork{r}#59 == fork1[KEYWORD]]
@@ -10259,7 +10258,7 @@ public void testPruneColumnsInForkBranchesShouldPruneNestedEvalsIfColumnIsDroppe
             | drop languages
             """;
         var plan = optimizedPlan(query);
-        var project = as(plan, EsqlProject.class);
+        var project = as(plan, Project.class);
         assertThat(project.projections().size(), equalTo(10));
         var limit = as(project.child(), Limit.class);
         var filter = as(limit.child(), Filter.class);
@@ -10314,7 +10313,7 @@ public void testPruneColumnsInForkBranchesShouldPruneNestedEvalsIfColumnIsDroppe
     }
 
     /**
-     * EsqlProject[[a{r}#45]]
+     * Project[[a{r}#45]]
      * \_Limit[1000[INTEGER],false,false]
      *   \_Fork[[a{r}#45]]
      *     |_Project[[a{r}#5]]
@@ -10334,7 +10333,7 @@ public void testPruneColumnsInForkBranchesKeepOnlyNeededAggs() {
              | KEEP a
             """;
         var plan = optimizedPlan(query);
-        var project = as(plan, EsqlProject.class);
+        var project = as(plan, Project.class);
         assertThat(project.projections().size(), equalTo(1));
         assertThat(Expressions.names(project.projections()), contains("a"));
         var limit = as(project.child(), Limit.class);
@@ -10703,7 +10702,7 @@ public void testPushDownLimitInForkPastEvalAndMvExpand() {
      * Optimized plan:
      * Limit[1000[INTEGER],false,false]
      * \_InlineJoin[LEFT,[],[]]
-     *   |_EsqlProject[[salary{f}#23, languages1{r}#7, languages{f}#21]]
+     *   |_Project[[salary{f}#23, languages1{r}#7, languages{f}#21]]
      *   | \_Eval[[MVAVG(languages{f}#21) AS languages1#7]]
      *   |   \_EsRelation[employees][_meta_field{f}#24, emp_no{f}#18, first_name{f}#19, ..]
      *   \_Project[[languages2{r}#14, avg{r}#17]]
@@ -10716,7 +10715,7 @@ public void testPushDownLimitInForkPastEvalAndMvExpand() {
      * Final plan execution:
      * Limit[1000[INTEGER],false,false]
      * \_Eval[[5.5[DOUBLE] AS languages2#14, 1[DOUBLE] AS avg#17]]
-     *   \_EsqlProject[[salary{f}#23, languages1{r}#7, languages{f}#21]]
+     *   \_Project[[salary{f}#23, languages1{r}#7, languages{f}#21]]
      *     \_Eval[[MVAVG(languages{f}#21) AS languages1#7]]
      *       \_EsRelation[employees][_meta_field{f}#24, emp_no{f}#18, first_name{f}#19, ..]
      */
@@ -10735,7 +10734,7 @@ public void testDoubleInlineStatsPrunning_With_MV_Functions() {
         var p = as(plan, Limit.class);
         var join = as(p.child(), InlineJoin.class);
         // Left
-        var leftProject = as(join.left(), EsqlProject.class);
+        var leftProject = as(join.left(), Project.class);
         assertMap(Expressions.names(leftProject.projections()), is(List.of("salary", "languages1", "languages")));
         var leftEval = as(leftProject.child(), Eval.class);
         var leftRelation = as(leftEval.child(), EsRelation.class);
@@ -10766,7 +10765,7 @@ public void testDoubleInlineStatsPrunning_With_MV_Functions() {
         p = as(newMainPlan, Limit.class);
         var eval = as(p.child(), Eval.class);
         assertMap(Expressions.names(eval.fields()), is(List.of("languages2", "avg")));
-        leftProject = as(eval.child(), EsqlProject.class);
+        leftProject = as(eval.child(), Project.class);
         assertMap(Expressions.names(leftProject.projections()), is(List.of("salary", "languages1", "languages")));
         var mvAvgEval = as(leftProject.child(), Eval.class);
         assertMap(Expressions.names(mvAvgEval.fields()), is(List.of("languages1")));
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/PhysicalPlanOptimizerTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/PhysicalPlanOptimizerTests.java
index 4d328f9385c2e..9907d2596ba61 100644
--- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/PhysicalPlanOptimizerTests.java
+++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/PhysicalPlanOptimizerTests.java
@@ -8422,7 +8422,7 @@ public void testLookupThenProject() {
      * 
{@code
      * TopN[[Order[name{r}#25,ASC,LAST], Order[emp_no{f}#14,ASC,LAST]],1000[INTEGER]]
      * \_Join[JoinConfig[type=LEFT OUTER, unionFields=[int{r}#4]]]
-     *   |_EsqlProject[[..., long_noidx{f}#23, salary{f}#19]]
+     *   |_Project[[..., long_noidx{f}#23, salary{f}#19]]
      *   | \_EsRelation[test][_meta_field{f}#20, emp_no{f}#14, first_name{f}#15, ..]
      *   \_LocalRelation[[int{f}#24, name{f}#25],[...]]
      * }
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/DeduplicateAggsTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/DeduplicateAggsTests.java index e656cc364691a..bbe4e13fb3a22 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/DeduplicateAggsTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/DeduplicateAggsTests.java @@ -311,7 +311,7 @@ public void testEliminateDuplicateRenamedGroupings() { /** * Expects *
{@code
-     * EsqlProject[[a{r}#5, c{r}#8]]
+     * Project[[a{r}#5, c{r}#8]]
      * \_Eval[[null[INTEGER] AS x]]
      *   \_EsRelation[test][_meta_field{f}#15, emp_no{f}#9, first_name{f}#10, g..]
      * }
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 e5a2300f4689f..7061ff5f8150b 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 @@ -27,9 +27,9 @@ import org.elasticsearch.xpack.esql.plan.logical.Eval; import org.elasticsearch.xpack.esql.plan.logical.Limit; 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.join.StubRelation; -import org.elasticsearch.xpack.esql.plan.logical.local.EsqlProject; import org.junit.BeforeClass; import java.util.List; @@ -75,7 +75,7 @@ public static void init() { * Limit[1000[INTEGER],false] * \_InlineJoin[LEFT,[y{r}#10],[y{r}#10],[y{r}#10]] * |_Eval[[gender{f}#13 AS y]] - * | \_EsqlProject[[emp_no{f}#11, languages{f}#14, gender{f}#13]] + * | \_Project[[emp_no{f}#11, languages{f}#14, gender{f}#13]] * | \_EsRelation[test][_meta_field{f}#17, emp_no{f}#11, first_name{f}#12, ..] * \_Aggregate[STANDARD,[y{r}#10],[MAX(languages{f}#14,true[BOOLEAN]) AS max_lang, y{r}#10]] * \_StubRelation[[emp_no{f}#11, languages{f}#14, gender{f}#13, y{r}#10]] @@ -91,7 +91,7 @@ public void testGroupingAliasingMoved_To_LeftSideOfJoin() { var limit = as(plan, Limit.class); var inline = as(limit.child(), InlineJoin.class); var leftEval = as(inline.left(), Eval.class); - var project = as(leftEval.child(), EsqlProject.class); + var project = as(leftEval.child(), Project.class); assertThat(Expressions.names(project.projections()), contains("emp_no", "languages", "gender")); @@ -116,7 +116,7 @@ public void testGroupingAliasingMoved_To_LeftSideOfJoin() { * r}#9]] * |_Eval[[LEFT(last_name{f}#27,1[INTEGER]) AS f, gender{f}#25 AS g]] * | \_Eval[[LEFT(first_name{f}#24,1[INTEGER]) AS first_name_l]] - * | \_EsqlProject[[emp_no{f}#23, languages{f}#26, gender{f}#25, last_name{f}#27, first_name{f}#24]] + * | \_Project[[emp_no{f}#23, languages{f}#26, gender{f}#25, last_name{f}#27, first_name{f}#24]] * | \_EsRelation[test][_meta_field{f}#29, emp_no{f}#23, first_name{f}#24, ..] * \_Aggregate[STANDARD,[f{r}#18, g{r}#21, first_name_l{r}#9],[MAX(languages{f}#26,true[BOOLEAN]) AS max_lang, MIN(languages{f} * #26,true[BOOLEAN]) AS min_lang, f{r}#18, g{r}#21, first_name_l{r}#9]] @@ -136,7 +136,7 @@ public void testGroupingAliasingMoved_To_LeftSideOfJoin_WithExpression() { var inline = as(limit.child(), InlineJoin.class); var leftEval1 = as(inline.left(), Eval.class); var leftEval2 = as(leftEval1.child(), Eval.class); - var project = as(leftEval2.child(), EsqlProject.class); + var project = as(leftEval2.child(), Project.class); assertThat(Expressions.names(project.projections()), contains("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/PushDownAndCombineFiltersTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/PushDownAndCombineFiltersTests.java index db73c173e2590..51482c314330e 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/PushDownAndCombineFiltersTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/PushDownAndCombineFiltersTests.java @@ -59,7 +59,6 @@ import org.elasticsearch.xpack.esql.plan.logical.join.JoinConfig; import org.elasticsearch.xpack.esql.plan.logical.join.JoinTypes; 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 org.elasticsearch.xpack.esql.plan.logical.local.LocalSupplier; @@ -136,11 +135,11 @@ public void testPushDownFilter() { Filter fa = new Filter(EMPTY, relation, conditionA); List projections = singletonList(getFieldAttribute("b")); - EsqlProject keep = new EsqlProject(EMPTY, fa, projections); + Project keep = new Project(EMPTY, fa, projections); Filter fb = new Filter(EMPTY, keep, conditionB); Filter combinedFilter = new Filter(EMPTY, relation, new And(EMPTY, conditionA, conditionB)); - assertEquals(new EsqlProject(EMPTY, combinedFilter, projections), new PushDownAndCombineFilters().apply(fb, optimizerContext)); + assertEquals(new Project(EMPTY, combinedFilter, projections), new PushDownAndCombineFilters().apply(fb, optimizerContext)); } public void testPushDownFilterPastRenamingProject() { @@ -259,11 +258,11 @@ public void testPushDownLikeRlikeFilter() { Filter fa = new Filter(EMPTY, relation, conditionA); List projections = singletonList(getFieldAttribute("b")); - EsqlProject keep = new EsqlProject(EMPTY, fa, projections); + Project keep = new Project(EMPTY, fa, projections); Filter fb = new Filter(EMPTY, keep, conditionB); Filter combinedFilter = new Filter(EMPTY, relation, new And(EMPTY, conditionA, conditionB)); - assertEquals(new EsqlProject(EMPTY, combinedFilter, projections), new PushDownAndCombineFilters().apply(fb, optimizerContext)); + assertEquals(new Project(EMPTY, combinedFilter, projections), new PushDownAndCombineFilters().apply(fb, optimizerContext)); } // from ... | where a > 1 | stats count(1) by b | where count(1) >= 3 and b < 2 @@ -1036,7 +1035,7 @@ public void testPushDownLookupJoinExpressionMultipleWhere() { * did its job of pushing down the filter (by copying the correct part of the left hand side to the right hand side to also include * the aforementioned filter). * - * EsqlProject[[avg{r}#5, languages{f}#15, salary{f}#17, emp_no{f}#12]] + * Project[[avg{r}#5, languages{f}#15, salary{f}#17, emp_no{f}#12]] * \_Limit[1000[INTEGER],false,false] * \_InlineJoin[LEFT,[languages{f}#15],[languages{r}#15]] * |_Filter[languages{f}#15 > 2[INTEGER]] @@ -1068,7 +1067,7 @@ public void testPushDown_OneGroupingFilter_PastInlineJoin() { var subPlansResults = new HashSet(); var firstSubPlan = InlineJoin.firstSubPlan(plan, subPlansResults).stubReplacedSubPlan(); - var project = as(plan, EsqlProject.class); + var project = as(plan, Project.class); var limit = as(project.child(), Limit.class); // InlineJoin left side @@ -1102,7 +1101,7 @@ public void testPushDown_OneGroupingFilter_PastInlineJoin() { } /* - * EsqlProject[[avg{r}#5, languages{f}#18, gender{f}#17, emp_no{f}#15]] + * Project[[avg{r}#5, languages{f}#18, gender{f}#17, emp_no{f}#15]] * \_Limit[1000[INTEGER],false,false] * \_Filter[emp_no{f}#15 > 10050[INTEGER]] * \_InlineJoin[LEFT,[languages{f}#18, gender{f}#17],[languages{r}#18, gender{r}#17]] @@ -1134,7 +1133,7 @@ public void testPushDown_SelectiveGroupingAndFilters_PastInlineJoin() { var subPlansResults = new HashSet(); var firstSubPlan = InlineJoin.firstSubPlan(plan, subPlansResults).stubReplacedSubPlan(); - var project = as(plan, EsqlProject.class); + var project = as(plan, Project.class); var limit = as(project.child(), Limit.class); // common filter, above InlineJoin @@ -1181,7 +1180,7 @@ public void testPushDown_SelectiveGroupingAndFilters_PastInlineJoin() { } /* - * EsqlProject[[avg{r}#5, languages{f}#18, gender{f}#17, emp_no{f}#15]] + * Project[[avg{r}#5, languages{f}#18, gender{f}#17, emp_no{f}#15]] * \_Limit[1000[INTEGER],false,false] * \_Filter[ISNOTNULL(gender{f}#17) OR emp_no{f}#15 > 10050[INTEGER]] * \_InlineJoin[LEFT,[languages{f}#18, gender{f}#17],[languages{r}#18, gender{r}#17]] @@ -1213,7 +1212,7 @@ public void testPushDown_SelectiveGroupingOrFilters_PastInlineJoin() { var subPlansResults = new HashSet(); var firstSubPlan = InlineJoin.firstSubPlan(plan, subPlansResults).stubReplacedSubPlan(); - var project = as(plan, EsqlProject.class); + var project = as(plan, Project.class); var limit = as(project.child(), Limit.class); // common filter, above InlineJoin @@ -1263,7 +1262,7 @@ public void testPushDown_SelectiveGroupingOrFilters_PastInlineJoin() { } /* - * EsqlProject[[avg{r}#7, languages{f}#21, gender{f}#20, emp_no{f}#18]] + * Project[[avg{r}#7, languages{f}#21, gender{f}#20, emp_no{f}#18]] * \_Limit[1000[INTEGER],false,false] * \_Filter[ISNOTNULL(gender{f}#20) OR emp_no{f}#18 > 10050[INTEGER] AND salary{f}#23 > 5000[INTEGER]] * \_InlineJoin[LEFT,[languages{f}#21, gender{f}#20],[languages{r}#21, gender{r}#20]] @@ -1296,7 +1295,7 @@ public void testPushDown_ComplexFiltering_CombinedWithLeftFiltering_PastInlineJo var subPlansResults = new HashSet(); var firstSubPlan = InlineJoin.firstSubPlan(plan, subPlansResults).stubReplacedSubPlan(); - var project = as(plan, EsqlProject.class); + var project = as(plan, Project.class); var limit = as(project.child(), Limit.class); // common filter, above InlineJoin @@ -1371,7 +1370,7 @@ public void testPushDown_ComplexFiltering_CombinedWithLeftFiltering_PastInlineJo } /* - * EsqlProject[[salary{f}#16, emp_no{f}#11]] + * Project[[salary{f}#16, emp_no{f}#11]] * \_Limit[1000[INTEGER],false,false] * \_InlineJoin[LEFT,[salary{f}#16],[salary{r}#16]] * |_Filter[salary{f}#16 < 10000[INTEGER] AND salary{f}#16 > 10000[INTEGER]] @@ -1396,7 +1395,7 @@ public void testPushDown_ImpossibleFilter_PastInlineJoin() { var subPlansResults = new HashSet(); var firstSubPlan = InlineJoin.firstSubPlan(plan, subPlansResults).stubReplacedSubPlan(); - var project = as(plan, EsqlProject.class); + var project = as(plan, Project.class); var limit = as(project.child(), Limit.class); // InlineJoin var ij = as(limit.child(), InlineJoin.class); @@ -1432,7 +1431,7 @@ public void testPushDown_ImpossibleFilter_PastInlineJoin() { } /* - * EsqlProject[[languages{f}#14, a{r}#5, gender{f}#13]] + * Project[[languages{f}#14, a{r}#5, gender{f}#13]] * \_Limit[1000[INTEGER],false,false] * \_Filter[languages{f}#14 > 2[INTEGER]] * \_InlineJoin[LEFT,[gender{f}#13],[gender{r}#13]] @@ -1462,7 +1461,7 @@ public void testDontPushDown_A_SimpleFilter_PastInlineJoin() { var subPlansResults = new HashSet(); var firstSubPlan = InlineJoin.firstSubPlan(plan, subPlansResults).stubReplacedSubPlan(); - var project = as(plan, EsqlProject.class); + var project = as(plan, Project.class); var limit = as(project.child(), Limit.class); // common filter, above InlineJoin var commonFilter = as(limit.child(), Filter.class); @@ -1495,7 +1494,7 @@ public void testDontPushDown_A_SimpleFilter_PastInlineJoin() { } /* - * EsqlProject[[avgByL{r}#5, avgByG{r}#9, languages{f}#20, gender{f}#19, emp_no{f}#17]] + * Project[[avgByL{r}#5, avgByG{r}#9, languages{f}#20, gender{f}#19, emp_no{f}#17]] * \_Limit[1000[INTEGER],false,false] * \_Filter[languages{f}#20 > 2[INTEGER]] * \_InlineJoin[LEFT,[gender{f}#19],[gender{r}#19]] @@ -1554,7 +1553,7 @@ public void testPartiallyPushDown_GroupingFilters_PastTwoInlineJoins1() { var subPlans = InlineJoin.firstSubPlan(plan, subPlansResults); var firstSubPlan = subPlans.stubReplacedSubPlan(); - var project = as(plan, EsqlProject.class); + var project = as(plan, Project.class); var limit = as(project.child(), Limit.class); // common filter, above first InlineJoin (inline stats ... by gender) @@ -1632,7 +1631,7 @@ public void testPartiallyPushDown_GroupingFilters_PastTwoInlineJoins1() { } /* - * EsqlProject[[avgByL{r}#5, avgByG{r}#9, languages{f}#22, gender{f}#21, emp_no{f}#19]] + * Project[[avgByL{r}#5, avgByG{r}#9, languages{f}#22, gender{f}#21, emp_no{f}#19]] * \_Limit[1000[INTEGER],false,false] * \_Filter[emp_no{f}#19 > 10050[INTEGER]] * \_InlineJoin[LEFT,[gender{f}#21, languages{f}#22],[gender{r}#21, languages{r}#22]] @@ -1695,7 +1694,7 @@ public void testPartiallyPushDown_GroupingFilters_PastTwoInlineJoins2() { var subPlans = InlineJoin.firstSubPlan(plan, subPlansResults); var firstSubPlan = subPlans.stubReplacedSubPlan(); - var project = as(plan, EsqlProject.class); + var project = as(plan, Project.class); var limit = as(project.child(), Limit.class); // common filter, above first InlineJoin (inline stats ... by gender, languages) @@ -1790,7 +1789,7 @@ public void testPartiallyPushDown_GroupingFilters_PastTwoInlineJoins2() { } /* - * EsqlProject[[avgByL{r}#5, avgByG{r}#9, languages{f}#22, gender{f}#21, emp_no{f}#19]] + * Project[[avgByL{r}#5, avgByG{r}#9, languages{f}#22, gender{f}#21, emp_no{f}#19]] * \_Limit[1000[INTEGER],false,false] * \_Filter[avgByL{r}#5 > 40000[INTEGER]] * \_InlineJoin[LEFT,[gender{f}#21, languages{f}#22],[gender{r}#21, languages{r}#22]] @@ -1853,7 +1852,7 @@ public void testPartiallyPushDown_GroupingFilters_PastTwoInlineJoins_ExcludeAggF var subPlans = InlineJoin.firstSubPlan(plan, subPlansResults); var firstSubPlan = subPlans.stubReplacedSubPlan(); - var project = as(plan, EsqlProject.class); + var project = as(plan, Project.class); var limit = as(project.child(), Limit.class); // common filter, above first InlineJoin (inline stats ... by gender, languages) @@ -1948,14 +1947,14 @@ public void testPartiallyPushDown_GroupingFilters_PastTwoInlineJoins_ExcludeAggF } /* - * EsqlProject[[avgByL{r}#9, avgByG{r}#16, lang{r}#13, gender{f}#28, emp_no{f}#26]] + * Project[[avgByL{r}#9, avgByG{r}#16, lang{r}#13, gender{f}#28, emp_no{f}#26]] * \_Limit[1000[INTEGER],false,false] * \_Filter[emp_no{f}#26 > 10050[INTEGER]] * \_InlineJoin[LEFT,[gender{f}#28, lang{r}#13],[gender{r}#28, lang{r}#13]] - * |_EsqlProject[[salary{f}#31, gender{f}#28, emp_no{f}#26, avgByL{r}#9, languages{f}#29 AS lang#13]] + * |_Project[[salary{f}#31, gender{f}#28, emp_no{f}#26, avgByL{r}#9, languages{f}#29 AS lang#13]] * | \_Filter[ISNOTNULL(gender{f}#28)] * | \_InlineJoin[LEFT,[languages{f}#29],[languages{r}#29]] - * | |_EsqlProject[[languages{f}#29, salary{f}#31, gender{f}#28, emp_no{f}#26]] + * | |_Project[[languages{f}#29, salary{f}#31, gender{f}#28, emp_no{f}#26]] * | | \_Filter[languages{f}#29 > 3[INTEGER]] * | | \_EsRelation[employees][_meta_field{f}#32, emp_no{f}#26, first_name{f}#27, ..] * | \_Project[[avgByL{r}#9, languages{f}#29]] @@ -1974,7 +1973,7 @@ public void testPartiallyPushDown_GroupingFilters_PastTwoInlineJoins_ExcludeAggF * \_Eval[[$$SUM$avgByL$0{r$}#38 / $$COUNT$avgByL$1{r$}#39 AS avgByL#9]] * \_Aggregate[[languages{f}#29],[SUM(salary{f}#31,true[BOOLEAN],PT0S[TIME_DURATION],compensated[KEYWORD]) AS * $$SUM$avgByL$0#38, COUNT(salary{f}#31,true[BOOLEAN],PT0S[TIME_DURATION]) AS $$COUNT$avgByL$1#39, languages{f}#29]] - * \_EsqlProject[[languages{f}#29, salary{f}#31, gender{f}#28, emp_no{f}#26]] + * \_Project[[languages{f}#29, salary{f}#31, gender{f}#28, emp_no{f}#26]] * \_Filter[languages{f}#29 > 3[INTEGER]] * \_EsRelation[employees][_meta_field{f}#32, emp_no{f}#26, first_name{f}#27, ..] * @@ -1982,10 +1981,10 @@ public void testPartiallyPushDown_GroupingFilters_PastTwoInlineJoins_ExcludeAggF * \_Eval[[$$SUM$avgByG$0{r$}#40 / $$COUNT$avgByG$1{r$}#41 AS avgByG#16]] * \_Aggregate[[gender{f}#28, lang{r}#13],[SUM(salary{f}#31,true[BOOLEAN],PT0S[TIME_DURATION],compensated[KEYWORD]) AS $$SUM$a * vgByG$0#40, COUNT(salary{f}#31,true[BOOLEAN],PT0S[TIME_DURATION]) AS $$COUNT$avgByG$1#41, gender{f}#28, lang{r}#13]] - * \_EsqlProject[[salary{f}#31, gender{f}#28, emp_no{f}#26, avgByL{r}#9, languages{f}#29 AS lang#13]] + * \_Project[[salary{f}#31, gender{f}#28, emp_no{f}#26, avgByL{r}#9, languages{f}#29 AS lang#13]] * \_Filter[ISNOTNULL(gender{f}#28)] * \_InlineJoin[LEFT,[languages{f}#29],[languages{r}#29]] - * |_EsqlProject[[languages{f}#29, salary{f}#31, gender{f}#28, emp_no{f}#26]] + * |_Project[[languages{f}#29, salary{f}#31, gender{f}#28, emp_no{f}#26]] * | \_Filter[languages{f}#29 > 3[INTEGER]] * | \_EsRelation[employees][_meta_field{f}#32, emp_no{f}#26, first_name{f}#27, ..] * \_LocalRelation[[avgByL{r}#9, languages{f}#29],org.elasticsearch.xpack.esql.plan.logical.local.CopyingLocalSupplier] @@ -2015,7 +2014,7 @@ public void testPartiallyPushDown_RenamedGroupingFilters_PastTwoInlineJoins() { var subPlans = InlineJoin.firstSubPlan(plan, subPlansResults); var firstSubPlan = subPlans.stubReplacedSubPlan(); - var project = as(plan, EsqlProject.class); + var project = as(plan, Project.class); var limit = as(project.child(), Limit.class); // common filter, above first InlineJoin (inline stats ... by gender, languages) @@ -2030,7 +2029,7 @@ public void testPartiallyPushDown_RenamedGroupingFilters_PastTwoInlineJoins() { // first InlineJoin left side var ij = as(commonFilter.child(), InlineJoin.class); // this is the projection that renames languages AS lang - var left = as(ij.left(), EsqlProject.class); + var left = as(ij.left(), Project.class); var projections = left.projections(); assertThat(Expressions.names(projections), contains("salary", "gender", "emp_no", "avgByL", "lang")); var langRename = as(projections.get(4), Alias.class); @@ -2047,7 +2046,7 @@ public void testPartiallyPushDown_RenamedGroupingFilters_PastTwoInlineJoins() { // second InlineJoin left side var innerIj = as(leftFilter.child(), InlineJoin.class); - var innerLeft = as(innerIj.left(), EsqlProject.class); + var innerLeft = as(innerIj.left(), Project.class); var innerProjections = innerLeft.projections(); assertThat(Expressions.names(innerProjections), contains("languages", "salary", "gender", "emp_no")); @@ -2073,7 +2072,7 @@ public void testPartiallyPushDown_RenamedGroupingFilters_PastTwoInlineJoins() { assertEquals(innerAggregate.groupings(), firstSubPlanInnerAggregate.groupings()); assertEquals(innerAggregate.aggregates(), firstSubPlanInnerAggregate.aggregates()); - var firstSubPlanInnerRelation = as(firstSubPlanInnerAggregate.child(), EsqlProject.class); + var firstSubPlanInnerRelation = as(firstSubPlanInnerAggregate.child(), Project.class); var firstSubPlanInnerProjections = firstSubPlanInnerRelation.projections(); assertThat(Expressions.names(firstSubPlanInnerProjections), contains("languages", "salary", "gender", "emp_no")); @@ -2122,7 +2121,7 @@ public void testPartiallyPushDown_RenamedGroupingFilters_PastTwoInlineJoins() { assertEquals(aggregate.groupings(), firstSubPlanAggregate.groupings()); assertEquals(aggregate.aggregates(), firstSubPlanAggregate.aggregates()); - var firstSubPlanProjection = as(ij.left(), EsqlProject.class); + var firstSubPlanProjection = as(ij.left(), Project.class); projections = firstSubPlanProjection.projections(); assertThat(Expressions.names(projections), contains("salary", "gender", "emp_no", "avgByL", "lang")); langRename = as(projections.get(4), Alias.class); @@ -2135,7 +2134,7 @@ public void testPartiallyPushDown_RenamedGroupingFilters_PastTwoInlineJoins() { } /* - * EsqlProject[[a{r}#5, gender{f}#12]] + * Project[[a{r}#5, gender{f}#12]] * \_Limit[1000[INTEGER],false,false] * \_Filter[a{r}#5 > 55000[INTEGER]] * \_InlineJoin[LEFT,[gender{f}#12],[gender{r}#12]] @@ -2156,7 +2155,7 @@ public void testDontPushDown_OnRightSideOf_InlineStats() { | KEEP a, gender """); - var project = as(plan, EsqlProject.class); + var project = as(plan, Project.class); var limit = as(project.child(), Limit.class); // common filter, above InlineJoin var commonFilter = as(limit.child(), Filter.class); @@ -2179,7 +2178,7 @@ public void testDontPushDown_OnRightSideOf_InlineStats() { } /* - * EsqlProject[[avgByL{r}#5, avgByG{r}#9, languages{f}#22, gender{f}#21, emp_no{f}#19]] + * Project[[avgByL{r}#5, avgByG{r}#9, languages{f}#22, gender{f}#21, emp_no{f}#19]] * \_Limit[1000[INTEGER],false,false] * \_Filter[languages{f}#22 > 3[INTEGER] AND avgByL{r}#5 > 40000[INTEGER] AND avgByG{r}#9 < 50000[INTEGER]] * \_InlineJoin[LEFT,[gender{f}#21],[gender{r}#21]] @@ -2238,7 +2237,7 @@ public void testPartiallyPushDown_GroupingFilters_PastTwoInlineJoins_ExcludeComp var subPlans = InlineJoin.firstSubPlan(plan, subPlansResults); var firstSubPlan = subPlans.stubReplacedSubPlan(); - var project = as(plan, EsqlProject.class); + var project = as(plan, Project.class); var limit = as(project.child(), Limit.class); // common filter, above first InlineJoin (inline stats ... by languages) @@ -2331,7 +2330,7 @@ public void testPartiallyPushDown_GroupingFilters_PastTwoInlineJoins_ExcludeComp } /* - * EsqlProject[[sum{r}#5, languages{f}#15, salary{f}#17]] + * Project[[sum{r}#5, languages{f}#15, salary{f}#17]] * \_Limit[1000[INTEGER],false,false] * \_InlineJoin[LEFT,[languages{f}#15],[languages{r}#15]] * |_Filter[languages{f}#15 > 2[INTEGER]] @@ -2358,7 +2357,7 @@ public void testPushDown_OneGroupingFilter_PastInlineJoinWithInnerFilter() { var subPlansResults = new HashSet(); var firstSubPlan = InlineJoin.firstSubPlan(plan, subPlansResults).stubReplacedSubPlan(); - var project = as(plan, EsqlProject.class); + var project = as(plan, Project.class); var limit = as(project.child(), Limit.class); // InlineJoin left side diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/PushDownFilterAndLimitIntoUnionAllTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/PushDownFilterAndLimitIntoUnionAllTests.java index f306527723b16..ab1a55d7c77f7 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/PushDownFilterAndLimitIntoUnionAllTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/PushDownFilterAndLimitIntoUnionAllTests.java @@ -37,7 +37,6 @@ import org.elasticsearch.xpack.esql.plan.logical.TopN; import org.elasticsearch.xpack.esql.plan.logical.UnionAll; import org.elasticsearch.xpack.esql.plan.logical.join.Join; -import org.elasticsearch.xpack.esql.plan.logical.local.EsqlProject; import org.elasticsearch.xpack.esql.plan.logical.local.LocalRelation; import org.junit.Before; @@ -57,14 +56,14 @@ public void checkSubqueryInFromCommandSupport() { *Limit[1000[INTEGER],false,false] * \_UnionAll[[_meta_field{r}#45, emp_no{r}#46, first_name{r}#47, gender{r}#48, hire_date{r}#49, job{r}#50, job.raw{r}#51, * languages{r}#52, last_name{r}#53, long_noidx{r}#54, salary{r}#55, language_code{r}#56, language_name{r}#57]] - * |_EsqlProject[[_meta_field{f}#12, emp_no{f}#6, first_name{f}#7, gender{f}#8, hire_date{f}#13, job{f}#14, job.raw{f}#15, + * |_Project[[_meta_field{f}#12, emp_no{f}#6, first_name{f}#7, gender{f}#8, hire_date{f}#13, job{f}#14, job.raw{f}#15, * languages{f}#9, last_name{f}#10, long_noidx{f}#16, salary{f}#11, language_code{r}#30, * language_name{r}#31]] * | \_Eval[[null[INTEGER] AS language_code#30, null[KEYWORD] AS language_name#31]] * | \_Limit[1000[INTEGER],false,false] * | \_Filter[emp_no{f}#6 > 10000[INTEGER]] * | \_EsRelation[test][_meta_field{f}#12, emp_no{f}#6, first_name{f}#7, ge..] - * |_EsqlProject[[_meta_field{f}#23, emp_no{f}#17, first_name{f}#18, gender{f}#19, hire_date{f}#24, job{f}#25, job.raw{f}#26, + * |_Project[[_meta_field{f}#23, emp_no{f}#17, first_name{f}#18, gender{f}#19, hire_date{f}#24, job{f}#25, job.raw{f}#26, * languages{f}#20, last_name{f}#21, long_noidx{f}#27, salary{f}#22, language_code{r}#32, * language_name{r}#33]] * | \_Eval[[null[INTEGER] AS language_code#32, null[KEYWORD] AS language_name#33]] @@ -86,7 +85,7 @@ public void testPushDownSimpleFilterPastUnionAll() { UnionAll unionAll = as(limit.child(), UnionAll.class); assertEquals(3, unionAll.children().size()); - EsqlProject child1 = as(unionAll.children().get(0), EsqlProject.class); + Project child1 = as(unionAll.children().get(0), Project.class); Eval eval = as(child1.child(), Eval.class); Limit childLimit = as(eval.child(), Limit.class); Filter childFilter = as(childLimit.child(), Filter.class); @@ -98,7 +97,7 @@ public void testPushDownSimpleFilterPastUnionAll() { EsRelation relation = as(childFilter.child(), EsRelation.class); assertEquals("test", relation.indexPattern()); - EsqlProject child2 = as(unionAll.children().get(1), EsqlProject.class); + Project child2 = as(unionAll.children().get(1), Project.class); eval = as(child2.child(), Eval.class); Subquery subquery = as(eval.child(), Subquery.class); childLimit = as(subquery.child(), Limit.class); @@ -124,11 +123,11 @@ public void testPushDownSimpleFilterPastUnionAll() { *Limit[1000[INTEGER],false,false] * \_UnionAll[[_meta_field{r}#27, emp_no{r}#28, first_name{r}#29, gender{r}#30, hire_date{r}#31, job{r}#32, job.raw{r}#33, * languages{r}#34, last_name{r}#35, long_noidx{r}#36, salary{r}#37]] - * |_EsqlProject[[_meta_field{f}#11, emp_no{f}#5, first_name{f}#6, gender{f}#7, hire_date{f}#12, job{f}#13, job.raw{f}#14, + * |_Project[[_meta_field{f}#11, emp_no{f}#5, first_name{f}#6, gender{f}#7, hire_date{f}#12, job{f}#13, job.raw{f}#14, * languages{f}#8, last_name{f}#9, long_noidx{f}#15, salary{f}#10]] * | \_Limit[1000[INTEGER],false,false] * | \_EsRelation[test][_meta_field{f}#11, emp_no{f}#5, first_name{f}#6, ge..] - * \_EsqlProject[[_meta_field{f}#22, emp_no{f}#16, first_name{f}#17, gender{f}#18, hire_date{f}#23, job{f}#24, job.raw{f}#25, + * \_Project[[_meta_field{f}#22, emp_no{f}#16, first_name{f}#17, gender{f}#18, hire_date{f}#23, job{f}#24, job.raw{f}#25, * languages{f}#19, last_name{f}#20, long_noidx{f}#26, salary{f}#21]] * \_Subquery[] * \_TopN[[Order[emp_no{f}#16,ASC,LAST]],1000[INTEGER],false] @@ -144,12 +143,12 @@ public void testPushDownLimitPastSubqueryWithSort() { UnionAll unionAll = as(limit.child(), UnionAll.class); assertEquals(2, unionAll.children().size()); - EsqlProject child1 = as(unionAll.children().get(0), EsqlProject.class); + Project child1 = as(unionAll.children().get(0), Project.class); Limit childLimit = as(child1.child(), Limit.class); EsRelation relation = as(childLimit.child(), EsRelation.class); assertEquals("test", relation.indexPattern()); - EsqlProject child2 = as(unionAll.children().get(1), EsqlProject.class); + Project child2 = as(unionAll.children().get(1), Project.class); Subquery subquery = as(child2.child(), Subquery.class); TopN topN = as(subquery.child(), TopN.class); Filter childFilter = as(topN.child(), Filter.class); @@ -166,12 +165,12 @@ public void testPushDownLimitPastSubqueryWithSort() { *Limit[1000[INTEGER],false,false] * \_UnionAll[[_meta_field{r}#28, emp_no{r}#29, first_name{r}#30, gender{r}#31, hire_date{r}#32, job{r}#33, job.raw{r}#34, * languages{r}#35, last_name{r}#36, long_noidx{r}#37, salary{r}#38]] - * |_EsqlProject[[_meta_field{f}#12, emp_no{f}#6, first_name{f}#7, gender{f}#8, hire_date{f}#13, job{f}#14, job.raw{f}#15, + * |_Project[[_meta_field{f}#12, emp_no{f}#6, first_name{f}#7, gender{f}#8, hire_date{f}#13, job{f}#14, job.raw{f}#15, * languages{f}#9, last_name{f}#10, long_noidx{f}#16, salary{f}#11]] * | \_Limit[1000[INTEGER],false,false] * | \_Filter[emp_no{f}#6 > 10000[INTEGER]] * | \_EsRelation[test][_meta_field{f}#12, emp_no{f}#6, first_name{f}#7, ge..] - * \_EsqlProject[[_meta_field{f}#23, emp_no{f}#17, first_name{f}#18, gender{f}#19, hire_date{f}#24, job{f}#25, job.raw{f}#26, + * \_Project[[_meta_field{f}#23, emp_no{f}#17, first_name{f}#18, gender{f}#19, hire_date{f}#24, job{f}#25, job.raw{f}#26, * languages{f}#20, last_name{f}#21, long_noidx{f}#27, salary{f}#22]] * \_Subquery[] * \_TopN[[Order[emp_no{f}#17,ASC,LAST]],1000[INTEGER],false] @@ -188,7 +187,7 @@ public void testPushDownFilterAndLimitPastSubqueryWithSort() { UnionAll unionAll = as(limit.child(), UnionAll.class); assertEquals(2, unionAll.children().size()); - EsqlProject child1 = as(unionAll.children().get(0), EsqlProject.class); + Project child1 = as(unionAll.children().get(0), Project.class); Limit childLimit = as(child1.child(), Limit.class); Filter childFilter = as(childLimit.child(), Filter.class); GreaterThan greaterThan = as(childFilter.condition(), GreaterThan.class); @@ -199,7 +198,7 @@ public void testPushDownFilterAndLimitPastSubqueryWithSort() { EsRelation relation = as(childFilter.child(), EsRelation.class); assertEquals("test", relation.indexPattern()); - EsqlProject child2 = as(unionAll.children().get(1), EsqlProject.class); + Project child2 = as(unionAll.children().get(1), Project.class); Subquery subquery = as(child2.child(), Subquery.class); TopN topN = as(subquery.child(), TopN.class); childFilter = as(topN.child(), Filter.class); @@ -222,14 +221,14 @@ public void testPushDownFilterAndLimitPastSubqueryWithSort() { *Limit[1000[INTEGER],false,false] * \_UnionAll[[_meta_field{r}#46, emp_no{r}#47, first_name{r}#48, gender{r}#49, hire_date{r}#50, job{r}#51, job.raw{r}#52, * languages{r}#53, last_name{r}#54, long_noidx{r}#55, salary{r}#56, language_code{r}#57, language_name{r}#58]] - * |_EsqlProject[[_meta_field{f}#13, emp_no{f}#7, first_name{f}#8, gender{f}#9, hire_date{f}#14, job{f}#15, job.raw{f}#16, + * |_Project[[_meta_field{f}#13, emp_no{f}#7, first_name{f}#8, gender{f}#9, hire_date{f}#14, job{f}#15, job.raw{f}#16, * languages{f}#10, last_name{f}#11, long_noidx{f}#17, salary{f}#12, language_code{r}#31, * language_name{r}#32]] * | \_Eval[[null[INTEGER] AS language_code#31, null[KEYWORD] AS language_name#32]] * | \_Limit[1000[INTEGER],false,false] * | \_Filter[emp_no{f}#7 > 10000[INTEGER] AND salary{f}#12 > 50000[INTEGER]] * | \_EsRelation[test][_meta_field{f}#13, emp_no{f}#7, first_name{f}#8, ge..] - * |_EsqlProject[[_meta_field{f}#24, emp_no{f}#18, first_name{f}#19, gender{f}#20, hire_date{f}#25, job{f}#26, job.raw{f}#27, + * |_Project[[_meta_field{f}#24, emp_no{f}#18, first_name{f}#19, gender{f}#20, hire_date{f}#25, job{f}#26, job.raw{f}#27, * languages{f}#21, last_name{f}#22, long_noidx{f}#28, salary{f}#23, language_code{r}#33, * language_name{r}#34]] * | \_Eval[[null[INTEGER] AS language_code#33, null[KEYWORD] AS language_name#34]] @@ -251,7 +250,7 @@ public void testPushDownConjunctiveFilterPastUnionAll() { UnionAll unionAll = as(limit.child(), UnionAll.class); assertEquals(3, unionAll.children().size()); - EsqlProject child1 = as(unionAll.children().get(0), EsqlProject.class); + Project child1 = as(unionAll.children().get(0), Project.class); Eval eval = as(child1.child(), Eval.class); Limit childLimit = as(eval.child(), Limit.class); Filter childFilter = as(childLimit.child(), Filter.class); @@ -269,7 +268,7 @@ public void testPushDownConjunctiveFilterPastUnionAll() { EsRelation relation = as(childFilter.child(), EsRelation.class); assertEquals("test", relation.indexPattern()); - EsqlProject child2 = as(unionAll.children().get(1), EsqlProject.class); + Project child2 = as(unionAll.children().get(1), Project.class); eval = as(child2.child(), Eval.class); Subquery subquery = as(eval.child(), Subquery.class); childLimit = as(subquery.child(), Limit.class); @@ -301,14 +300,14 @@ public void testPushDownConjunctiveFilterPastUnionAll() { *Limit[1000[INTEGER],false,false] * \_UnionAll[[_meta_field{r}#46, emp_no{r}#47, first_name{r}#48, gender{r}#49, hire_date{r}#50, job{r}#51, job.raw{r}#52, * languages{r}#53, last_name{r}#54, long_noidx{r}#55, salary{r}#56, language_code{r}#57, language_name{r}#58]] - * |_EsqlProject[[_meta_field{f}#13, emp_no{f}#7, first_name{f}#8, gender{f}#9, hire_date{f}#14, job{f}#15, job.raw{f}#16, + * |_Project[[_meta_field{f}#13, emp_no{f}#7, first_name{f}#8, gender{f}#9, hire_date{f}#14, job{f}#15, job.raw{f}#16, * languages{f}#10, last_name{f}#11, long_noidx{f}#17, salary{f}#12, language_code{r}#31, * language_name{r}#32]] * | \_Eval[[null[INTEGER] AS language_code#31, null[KEYWORD] AS language_name#32]] * | \_Limit[1000[INTEGER],false,false] * | \_Filter[emp_no{f}#7 > 10000[INTEGER] OR salary{f}#12 > 50000[INTEGER]] * | \_EsRelation[test][_meta_field{f}#13, emp_no{f}#7, first_name{f}#8, ge..] - * |_EsqlProject[[_meta_field{f}#24, emp_no{f}#18, first_name{f}#19, gender{f}#20, hire_date{f}#25, job{f}#26, job.raw{f}#27, + * |_Project[[_meta_field{f}#24, emp_no{f}#18, first_name{f}#19, gender{f}#20, hire_date{f}#25, job{f}#26, job.raw{f}#27, * languages{f}#21, last_name{f}#22, long_noidx{f}#28, salary{f}#23, language_code{r}#33, * language_name{r}#34]] * | \_Eval[[null[INTEGER] AS language_code#33, null[KEYWORD] AS language_name#34]] @@ -330,7 +329,7 @@ public void testPushDownDisjunctiveFilterPastUnionAll() { UnionAll unionAll = as(limit.child(), UnionAll.class); assertEquals(3, unionAll.children().size()); - EsqlProject child1 = as(unionAll.children().get(0), EsqlProject.class); + Project child1 = as(unionAll.children().get(0), Project.class); Eval eval = as(child1.child(), Eval.class); Limit childLimit = as(eval.child(), Limit.class); Filter childFilter = as(childLimit.child(), Filter.class); @@ -348,7 +347,7 @@ public void testPushDownDisjunctiveFilterPastUnionAll() { EsRelation relation = as(childFilter.child(), EsRelation.class); assertEquals("test", relation.indexPattern()); - EsqlProject child2 = as(unionAll.children().get(1), EsqlProject.class); + Project child2 = as(unionAll.children().get(1), Project.class); eval = as(child2.child(), Eval.class); Subquery subquery = as(eval.child(), Subquery.class); childLimit = as(subquery.child(), Limit.class); @@ -380,14 +379,14 @@ public void testPushDownDisjunctiveFilterPastUnionAll() { *Limit[1000[INTEGER],false,false] * \_UnionAll[[_meta_field{r}#46, emp_no{r}#47, first_name{r}#48, gender{r}#49, hire_date{r}#50, job{r}#51, job.raw{r}#52, * languages{r}#53, last_name{r}#54, long_noidx{r}#55, salary{r}#56, language_code{r}#57, language_name{r}#58]] - * |_EsqlProject[[_meta_field{f}#13, emp_no{f}#7, first_name{f}#8, gender{f}#9, hire_date{f}#14, job{f}#15, job.raw{f}#16, + * |_Project[[_meta_field{f}#13, emp_no{f}#7, first_name{f}#8, gender{f}#9, hire_date{f}#14, job{f}#15, job.raw{f}#16, * languages{f}#10, last_name{f}#11, long_noidx{f}#17, salary{f}#12, language_code{r}#31, * language_name{r}#32]] * | \_Eval[[null[INTEGER] AS language_code#31, null[KEYWORD] AS language_name#32]] * | \_Limit[1000[INTEGER],false,false] * | \_Filter[emp_no{f}#7 > 10000[INTEGER] AND salary{f}#12 < 50000[INTEGER]] * | \_EsRelation[test][_meta_field{f}#13, emp_no{f}#7, first_name{f}#8, ge..] - * |_EsqlProject[[_meta_field{f}#24, emp_no{f}#18, first_name{f}#19, gender{f}#20, hire_date{f}#25, job{f}#26, job.raw{f}#27, + * |_Project[[_meta_field{f}#24, emp_no{f}#18, first_name{f}#19, gender{f}#20, hire_date{f}#25, job{f}#26, job.raw{f}#27, * languages{f}#21, last_name{f}#22, long_noidx{f}#28, salary{f}#23, language_code{r}#33, * language_name{r}#34]] * | \_Eval[[null[INTEGER] AS language_code#33, null[KEYWORD] AS language_name#34]] @@ -409,7 +408,7 @@ public void testPushDownFilterPastUnionAllAndCombineWithFilterInSubquery() { UnionAll unionAll = as(limit.child(), UnionAll.class); assertEquals(3, unionAll.children().size()); - EsqlProject child1 = as(unionAll.children().get(0), EsqlProject.class); + Project child1 = as(unionAll.children().get(0), Project.class); Eval eval = as(child1.child(), Eval.class); Limit childLimit = as(eval.child(), Limit.class); Filter childFilter = as(childLimit.child(), Filter.class); @@ -427,7 +426,7 @@ public void testPushDownFilterPastUnionAllAndCombineWithFilterInSubquery() { EsRelation relation = as(childFilter.child(), EsRelation.class); assertEquals("test", relation.indexPattern()); - EsqlProject child2 = as(unionAll.children().get(1), EsqlProject.class); + Project child2 = as(unionAll.children().get(1), Project.class); eval = as(child2.child(), Eval.class); Subquery subquery = as(eval.child(), Subquery.class); childLimit = as(subquery.child(), Limit.class); @@ -461,7 +460,7 @@ public void testPushDownFilterPastUnionAllAndCombineWithFilterInSubquery() { * languages{f}#48, last_name{f}#49, long_noidx{f}#55, salary{f}#50, x{r}#82, * $$x$converted_to$long{r}#117, y{r}#127, $$y$converted_to$long{r}#118, z{r}#84, * language_name{r}#85],EMPTY] - * |_EsqlProject[[_meta_field{f}#62, emp_no{f}#56, first_name{f}#57, gender{f}#58, hire_date{f}#63, job{f}#64, job.raw{f}#65, + * |_Project[[_meta_field{f}#62, emp_no{f}#56, first_name{f}#57, gender{f}#58, hire_date{f}#63, job{f}#64, job.raw{f}#65, * languages{f}#59, last_name{f}#60, long_noidx{f}#66, salary{f}#61, x{r}#5, $$x$converted_to$long{r}#119, * y{r}#128, $$y$converted_to$long{r}#120, z{r}#11, language_name{r}#86]] * | \_Filter[ISNOTNULL($$y$converted_to$long{r}#120)] @@ -475,7 +474,7 @@ public void testPushDownFilterPastUnionAllAndCombineWithFilterInSubquery() { * | \_Eval[[1[INTEGER] AS x#5, emp_no{f}#56 + 1[INTEGER] AS z#11]] * | \_Filter[salary{f}#61 < 100000[INTEGER]] * | \_EsRelation[test][_meta_field{f}#62, emp_no{f}#56, first_name{f}#57, ..] - * |_EsqlProject[[_meta_field{r}#87, emp_no{r}#88, first_name{r}#89, gender{r}#90, hire_date{r}#91, job{r}#92, job.raw{r}#93, + * |_Project[[_meta_field{r}#87, emp_no{r}#88, first_name{r}#89, gender{r}#90, hire_date{r}#91, job{r}#92, job.raw{r}#93, * languages{r}#94, last_name{r}#95, long_noidx{r}#96, salary{r}#97, x{r}#22, $$x$converted_to$long{r}#121, * y{r}#129, $$y$converted_to$long{r}#122, z{r}#17, language_name{r}#98]] * | \_Filter[ISNOTNULL($$y$converted_to$long{r}#122)] @@ -490,7 +489,7 @@ public void testPushDownFilterPastUnionAllAndCombineWithFilterInSubquery() { * | \_Filter[z{r}#17 > 0[INTEGER]] * | \_Aggregate[[language_code{f}#67],[COUNT(*[KEYWORD],true[BOOLEAN]) AS y#20, language_code{f}#67 AS z#17]] * | \_EsRelation[languages][language_code{f}#67, language_name{f}#68] - * \_EsqlProject[[_meta_field{f}#75, emp_no{r}#99, first_name{f}#70, gender{f}#71, hire_date{f}#76, job{f}#77, job.raw{f}#78, + * \_Project[[_meta_field{f}#75, emp_no{r}#99, first_name{f}#70, gender{f}#71, hire_date{f}#76, job{f}#77, job.raw{f}#78, * languages{r}#100, last_name{f}#73, long_noidx{f}#79, salary{r}#101, x{r}#29, * $$x$converted_to$long{r}#123, y{r}#130, $$y$converted_to$long{r}#124, z{r}#35, language_name{f}#81]] * \_Filter[ISNOTNULL($$x$converted_to$long{r}#123) AND ISNOTNULL($$y$converted_to$long{r}#124)] @@ -535,7 +534,7 @@ public void testPushDownFilterOnReferenceAttributesPastUnionAll() { LocalRelation child1 = as(unionAll.children().get(0), LocalRelation.class); - EsqlProject child2 = as(unionAll.children().get(1), EsqlProject.class); + Project child2 = as(unionAll.children().get(1), Project.class); Filter filter = as(child2.child(), Filter.class); IsNotNull isNotNull = as(filter.condition(), IsNotNull.class); ReferenceAttribute y = as(isNotNull.field(), ReferenceAttribute.class); @@ -574,7 +573,7 @@ public void testPushDownFilterOnReferenceAttributesPastUnionAll() { EsRelation relation = as(childFilter.child(), EsRelation.class); assertEquals("test", relation.indexPattern()); - EsqlProject child3 = as(unionAll.children().get(2), EsqlProject.class); + Project child3 = as(unionAll.children().get(2), Project.class); filter = as(child3.child(), Filter.class); isNotNull = as(filter.condition(), IsNotNull.class); y = as(isNotNull.field(), ReferenceAttribute.class); @@ -601,7 +600,7 @@ public void testPushDownFilterOnReferenceAttributesPastUnionAll() { relation = as(aggregate.child(), EsRelation.class); assertEquals("languages", relation.indexPattern()); - EsqlProject child4 = as(unionAll.children().get(3), EsqlProject.class); + Project child4 = as(unionAll.children().get(3), Project.class); filter = as(child4.child(), Filter.class); And and = as(filter.condition(), And.class); isNotNull = as(and.left(), IsNotNull.class); @@ -636,7 +635,7 @@ public void testPushDownFilterOnReferenceAttributesPastUnionAll() { * languages{r}#43, last_name{r}#44, long_noidx{r}#45, salary{r}#46, x{r}#47, y{r}#48]] * |_LocalRelation[[_meta_field{f}#18, emp_no{f}#12, first_name{f}#13, gender{f}#14, hire_date{f}#19, job{f}#20, job.raw{f}#21, * languages{f}#15, last_name{f}#16, long_noidx{f}#22, salary{f}#17, x{r}#34, y{r}#35],EMPTY] - * \_EsqlProject[[_meta_field{f}#29, emp_no{f}#23, first_name{f}#24, gender{f}#25, hire_date{f}#30, job{f}#31, job.raw{f}#32, + * \_Project[[_meta_field{f}#29, emp_no{f}#23, first_name{f}#24, gender{f}#25, hire_date{f}#30, job{f}#31, job.raw{f}#32, * languages{f}#26, last_name{f}#27, long_noidx{f}#33, salary{f}#28, x{r}#5, y{r}#8]] * \_Subquery[] * \_Limit[1000[INTEGER],false,false] @@ -657,7 +656,7 @@ public void testPushDownFilterOnReferenceAttributesAndFieldAttributesPastUnionAl LocalRelation child1 = as(unionAll.children().get(0), LocalRelation.class); - EsqlProject child2 = as(unionAll.children().get(1), EsqlProject.class); + Project child2 = as(unionAll.children().get(1), Project.class); Subquery subquery = as(child2.child(), Subquery.class); Limit childLimit = as(subquery.child(), Limit.class); Filter childFilter = as(childLimit.child(), Filter.class); @@ -707,7 +706,7 @@ public void testPushDownFilterOnReferenceAttributesAndFieldAttributesPastUnionAl * birth_date{r}#79, height{r}#80, height.double{r}#81, height.half_float{r}#82, height.scaled_float{r}#83, * is_rehired{r}#84, job_positions{r}#85, languages.int{r}#86, languages.long{r}#87, languages.short{r}#88, * salary_change{r}#89, still_hired{r}#90]] - * |_EsqlProject[[_meta_field{f}#25, emp_no{r}#100, $$emp_no$converted_to$double{r}#91, $$emp_no$converted_to$long{r}#92, + * |_Project[[_meta_field{f}#25, emp_no{r}#100, $$emp_no$converted_to$double{r}#91, $$emp_no$converted_to$long{r}#92, * first_name{r}#101, gender{f}#21, $$gender$converted_to$keyword{r}#93, hire_date{r}#102, job{f}#27, * job.raw{f}#28, languages{f}#22, last_name{r}#103, long_noidx{f}#29, salary{r}#104, * avg_worked_seconds{r}#50, birth_date{r}#51, height{r}#52, height.double{r}#53, @@ -771,7 +770,7 @@ public void testFilterOnMixedDataTypesFields() { UnionAll unionAll = as(filter.child(), UnionAll.class); assertEquals(2, unionAll.children().size()); - EsqlProject child1 = as(unionAll.children().get(0), EsqlProject.class); + Project child1 = as(unionAll.children().get(0), Project.class); Eval eval = as(child1.child(), Eval.class); limit = as(eval.child(), Limit.class); EsRelation relation = as(limit.child(), EsRelation.class); @@ -795,12 +794,12 @@ public void testFilterOnMixedDataTypesFields() { * Limit[1000[INTEGER],false,false] * \_UnionAll[[_meta_field{r}#27, emp_no{r}#28, first_name{r}#29, gender{r}#30, hire_date{r}#31, job{r}#32, job.raw{r}#33, * languages{r}#34, last_name{r}#35, long_noidx{r}#36, salary{r}#37]] - * |_EsqlProject[[_meta_field{f}#11, emp_no{f}#5, first_name{f}#6, gender{f}#7, hire_date{f}#12, job{f}#13, job.raw{f}#14, + * |_Project[[_meta_field{f}#11, emp_no{f}#5, first_name{f}#6, gender{f}#7, hire_date{f}#12, job{f}#13, job.raw{f}#14, * languages{f}#8, last_name{f}#9, long_noidx{f}#15, salary{f}#10]] * | \_Limit[1000[INTEGER],false,false] * | \_Filter[:(first_name{f}#6,first[KEYWORD])] * | \_EsRelation[test][_meta_field{f}#11, emp_no{f}#5, first_name{f}#6, ge..] - * \_EsqlProject[[_meta_field{f}#22, emp_no{f}#16, first_name{f}#17, gender{f}#18, hire_date{f}#23, job{f}#24, job.raw{f}#25, + * \_Project[[_meta_field{f}#22, emp_no{f}#16, first_name{f}#17, gender{f}#18, hire_date{f}#23, job{f}#24, job.raw{f}#25, * languages{f}#19, last_name{f}#20, long_noidx{f}#26, salary{f}#21]] * \_Subquery[] * \_Limit[1000[INTEGER],false,false] @@ -817,7 +816,7 @@ public void testPushDownSingleFullTextFunctionPastUnionAll() { UnionAll unionAll = as(limit.child(), UnionAll.class); assertEquals(2, unionAll.children().size()); - EsqlProject child1 = as(unionAll.children().get(0), EsqlProject.class); + Project child1 = as(unionAll.children().get(0), Project.class); Limit childLimit = as(child1.child(), Limit.class); Filter childFilter = as(childLimit.child(), Filter.class); MatchOperator match = as(childFilter.condition(), MatchOperator.class); @@ -828,7 +827,7 @@ public void testPushDownSingleFullTextFunctionPastUnionAll() { EsRelation relation = as(childFilter.child(), EsRelation.class); assertEquals("test", relation.indexPattern()); - EsqlProject child2 = as(unionAll.children().get(1), EsqlProject.class); + Project child2 = as(unionAll.children().get(1), Project.class); Subquery subquery = as(child2.child(), Subquery.class); childLimit = as(subquery.child(), Limit.class); childFilter = as(childLimit.child(), Filter.class); @@ -851,12 +850,12 @@ public void testPushDownSingleFullTextFunctionPastUnionAll() { * Limit[1000[INTEGER],false,false] * \_UnionAll[[_meta_field{r}#26, emp_no{r}#27, first_name{r}#28, gender{r}#29, hire_date{r}#30, job{r}#31, job.raw{r}#32, * languages{r}#33, last_name{r}#34, long_noidx{r}#35, salary{r}#36]] - * |_EsqlProject[[_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, + * |_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, * languages{f}#7, last_name{f}#8, long_noidx{f}#14, salary{f}#9]] * | \_Limit[1000[INTEGER],false,false] * | \_Filter[QSTR(first_name:first[KEYWORD]) AND KQL(last_name:last[KEYWORD])] * | \_EsRelation[test][_meta_field{f}#10, emp_no{f}#4, first_name{f}#5, ge..] - * \_EsqlProject[[_meta_field{f}#21, emp_no{f}#15, first_name{f}#16, gender{f}#17, hire_date{f}#22, job{f}#23, job.raw{f}#24, + * \_Project[[_meta_field{f}#21, emp_no{f}#15, first_name{f}#16, gender{f}#17, hire_date{f}#22, job{f}#23, job.raw{f}#24, * languages{f}#18, last_name{f}#19, long_noidx{f}#25, salary{f}#20]] * \_Subquery[] * \_Limit[1000[INTEGER],false,false] @@ -874,7 +873,7 @@ public void testPushDownFullTextFunctionNoFieldRequiredPastUnionAll() { UnionAll unionAll = as(limit.child(), UnionAll.class); assertEquals(2, unionAll.children().size()); - EsqlProject child1 = as(unionAll.children().get(0), EsqlProject.class); + Project child1 = as(unionAll.children().get(0), Project.class); Limit childLimit = as(child1.child(), Limit.class); Filter childFilter = as(childLimit.child(), Filter.class); And and = as(childFilter.condition(), And.class); @@ -888,7 +887,7 @@ public void testPushDownFullTextFunctionNoFieldRequiredPastUnionAll() { EsRelation relation = as(childFilter.child(), EsRelation.class); assertEquals("test", relation.indexPattern()); - EsqlProject child2 = as(unionAll.children().get(1), EsqlProject.class); + Project child2 = as(unionAll.children().get(1), Project.class); Subquery subquery = as(child2.child(), Subquery.class); childLimit = as(subquery.child(), Limit.class); childFilter = as(childLimit.child(), Filter.class); @@ -918,12 +917,12 @@ public void testPushDownFullTextFunctionNoFieldRequiredPastUnionAll() { * Limit[1000[INTEGER],false,false] * \_UnionAll[[_meta_field{r}#28, emp_no{r}#29, first_name{r}#30, gender{r}#31, hire_date{r}#32, job{r}#33, job.raw{r}#34, * languages{r}#35, last_name{r}#36, long_noidx{r}#37, salary{r}#38]] - * |_EsqlProject[[_meta_field{f}#12, emp_no{f}#6, first_name{f}#7, gender{f}#8, hire_date{f}#13, job{f}#14, job.raw{f}#15, + * |_Project[[_meta_field{f}#12, emp_no{f}#6, first_name{f}#7, gender{f}#8, hire_date{f}#13, job{f}#14, job.raw{f}#15, * languages{f}#9, last_name{f}#10, long_noidx{f}#16, salary{f}#11]] * | \_Limit[1000[INTEGER],false,false] * | \_Filter[:(first_name{f}#7,first[KEYWORD]) AND MATCH(last_name{f}#10,last[KEYWORD]) AND QSTR(gender:female[KEYWORD])] * | \_EsRelation[test][_meta_field{f}#12, emp_no{f}#6, first_name{f}#7, ge..] - * \_EsqlProject[[_meta_field{f}#23, emp_no{f}#17, first_name{f}#18, gender{f}#19, hire_date{f}#24, job{f}#25, job.raw{f}#26, + * \_Project[[_meta_field{f}#23, emp_no{f}#17, first_name{f}#18, gender{f}#19, hire_date{f}#24, job{f}#25, job.raw{f}#26, * languages{f}#20, last_name{f}#21, long_noidx{f}#27, salary{f}#22]] * \_Subquery[] * \_Limit[1000[INTEGER],false,false] @@ -941,7 +940,7 @@ public void testPushDownConjunctiveFullTextFunctionPastUnionAll() { UnionAll unionAll = as(limit.child(), UnionAll.class); assertEquals(2, unionAll.children().size()); - EsqlProject child1 = as(unionAll.children().get(0), EsqlProject.class); + Project child1 = as(unionAll.children().get(0), Project.class); Limit childLimit = as(child1.child(), Limit.class); Filter childFilter = as(childLimit.child(), Filter.class); And and = as(childFilter.condition(), And.class); @@ -962,7 +961,7 @@ public void testPushDownConjunctiveFullTextFunctionPastUnionAll() { EsRelation relation = as(childFilter.child(), EsRelation.class); assertEquals("test", relation.indexPattern()); - EsqlProject child2 = as(unionAll.children().get(1), EsqlProject.class); + Project child2 = as(unionAll.children().get(1), Project.class); Subquery subquery = as(child2.child(), Subquery.class); childLimit = as(subquery.child(), Limit.class); childFilter = as(childLimit.child(), Filter.class); @@ -995,12 +994,12 @@ public void testPushDownConjunctiveFullTextFunctionPastUnionAll() { * Limit[1000[INTEGER],false,false] * \_UnionAll[[_meta_field{r}#29, emp_no{r}#30, first_name{r}#31, gender{r}#32, hire_date{r}#33, job{r}#34, job.raw{r}#35, * languages{r}#36, last_name{r}#37, long_noidx{r}#38, salary{r}#39]] - * |_EsqlProject[[_meta_field{f}#13, emp_no{f}#7, first_name{f}#8, gender{f}#9, hire_date{f}#14, job{f}#15, job.raw{f}#16, + * |_Project[[_meta_field{f}#13, emp_no{f}#7, first_name{f}#8, gender{f}#9, hire_date{f}#14, job{f}#15, job.raw{f}#16, * languages{f}#10, last_name{f}#11, long_noidx{f}#17, salary{f}#12]] * | \_Limit[1000[INTEGER],false,false] * | \_Filter[:(first_name{f}#8,first[KEYWORD]) OR MatchPhrase(last_name{f}#11,last[KEYWORD]) OR KQL(gender:female[KEYWORD])] * | \_EsRelation[test][_meta_field{f}#13, emp_no{f}#7, first_name{f}#8, ge..] - * \_EsqlProject[[_meta_field{f}#24, emp_no{f}#18, first_name{f}#19, gender{f}#20, hire_date{f}#25, job{f}#26, job.raw{f}#27, + * \_Project[[_meta_field{f}#24, emp_no{f}#18, first_name{f}#19, gender{f}#20, hire_date{f}#25, job{f}#26, job.raw{f}#27, * languages{f}#21, last_name{f}#22, long_noidx{f}#28, salary{f}#23]] * \_Subquery[] * \_Limit[1000[INTEGER],false,false] @@ -1018,7 +1017,7 @@ public void testPushDownDisjunctiveFullTextFunctionPastUnionAll() { UnionAll unionAll = as(limit.child(), UnionAll.class); assertEquals(2, unionAll.children().size()); - EsqlProject child1 = as(unionAll.children().get(0), EsqlProject.class); + Project child1 = as(unionAll.children().get(0), Project.class); Limit childLimit = as(child1.child(), Limit.class); Filter childFilter = as(childLimit.child(), Filter.class); Or or = as(childFilter.condition(), Or.class); @@ -1039,7 +1038,7 @@ public void testPushDownDisjunctiveFullTextFunctionPastUnionAll() { EsRelation relation = as(childFilter.child(), EsRelation.class); assertEquals("test", relation.indexPattern()); - EsqlProject child2 = as(unionAll.children().get(1), EsqlProject.class); + Project child2 = as(unionAll.children().get(1), Project.class); Subquery subquery = as(child2.child(), Subquery.class); childLimit = as(subquery.child(), Limit.class); childFilter = as(childLimit.child(), Filter.class); @@ -1093,7 +1092,7 @@ public void testFullTextFunctionCanBePushedDownPastUnionAll() { LocalRelation child1 = as(unionAll.children().get(0), LocalRelation.class); // Second child: languages subquery with MATCH filter pushed down - EsqlProject child2 = as(unionAll.children().get(1), EsqlProject.class); + Project child2 = as(unionAll.children().get(1), Project.class); Eval eval2 = as(child2.child(), Eval.class); List aliases = eval2.fields(); assertEquals(11, aliases.size()); diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/ReplaceAliasingEvalWithProjectTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/ReplaceAliasingEvalWithProjectTests.java index 0c204a4687a7b..e6736bcacff03 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/ReplaceAliasingEvalWithProjectTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/ReplaceAliasingEvalWithProjectTests.java @@ -29,7 +29,7 @@ public class ReplaceAliasingEvalWithProjectTests extends AbstractLogicalPlanOptimizerTests { /** *
{@code
-     * EsqlProject[[emp_no{f}#18, salary{f}#23, emp_no{f}#18 AS emp_no2#7, salary2{r}#10, emp_no{f}#18 AS emp_no3#13, salary3{r}#16]]
+     * Project[[emp_no{f}#18, salary{f}#23, emp_no{f}#18 AS emp_no2#7, salary2{r}#10, emp_no{f}#18 AS emp_no3#13, salary3{r}#16]]
      * \_Eval[[salary{f}#23 * 2[INTEGER] AS salary2#10, salary2{r}#10 * 3[INTEGER] AS salary3#16]]
      *   \_Limit[1000[INTEGER],false,false]
      *     \_EsRelation[test][_meta_field{f}#24, emp_no{f}#18, first_name{f}#19, ..]
@@ -76,7 +76,7 @@ public void testSimple() {
 
     /**
      * 
{@code
-     * EsqlProject[[emp_no{f}#19, salary{f}#35, emp_no{f}#19 AS emp_no2#8, salary2{r}#11, emp_no{f}#19 AS emp_no3#14, salary3{r}#17]]
+     * Project[[emp_no{f}#19, salary{f}#35, emp_no{f}#19 AS emp_no2#8, salary2{r}#11, emp_no{f}#19 AS emp_no3#14, salary3{r}#17]]
      * \_Eval[[salary{f}#35 * 2[INTEGER] AS salary2#11, salary2{r}#11 * 3[INTEGER] AS salary3#17]]
      *   \_Limit[1000[INTEGER],true,false]
      *     \_Join[LEFT,[emp_no{f}#19],[emp_no{f}#30],null]
@@ -127,7 +127,7 @@ public void testSimpleFieldFromLookup() {
 
     /**
      * 
{@code
-     * EsqlProject[[emp_no{f}#24 AS emp_no2#7, salary{f}#29 AS salary2#10, emp_no{f}#24 AS emp_no3#13, emp_no{f}#24 AS salary#16,
+     * Project[[emp_no{f}#24 AS emp_no2#7, salary{f}#29 AS salary2#10, emp_no{f}#24 AS emp_no3#13, emp_no{f}#24 AS salary#16,
      *  salary{f}#29 AS salary3#19, salary{f}#29 AS emp_no#22]]
      * \_Limit[1000[INTEGER],false,false]
      *   \_EsRelation[test][_meta_field{f}#30, emp_no{f}#24, first_name{f}#25, ..]
@@ -160,7 +160,7 @@ public void testOnlyAliases() {
 
     /**
      * 
{@code
-     * EsqlProject[[emp_no{f}#26 AS b#21, emp_no{f}#26 AS a#24]]
+     * Project[[emp_no{f}#26 AS b#21, emp_no{f}#26 AS a#24]]
      * \_Limit[1000[INTEGER],false,false]
      *   \_EsRelation[test][_meta_field{f}#32, emp_no{f}#26, first_name{f}#27, ..]
      * }
@@ -188,7 +188,7 @@ public void testAliasLoopTwoVars() { /** *
{@code
-     * EsqlProject[[emp_no{f}#17 AS b#9, emp_no{f}#17 AS c#12, emp_no{f}#17 AS a#15]]
+     * Project[[emp_no{f}#17 AS b#9, emp_no{f}#17 AS c#12, emp_no{f}#17 AS a#15]]
      * \_Limit[1000[INTEGER],false,false]
      *   \_EsRelation[test][_meta_field{f}#23, emp_no{f}#17, first_name{f}#18, ..]
      * }
@@ -217,7 +217,7 @@ public void testAliasLoopThreeVars() { /** *
{@code
-     * EsqlProject[[salary{f}#23, emp_no{f}#18 AS emp_no2#7, $$emp_no$temp_name$29{r}#30 AS emp_no#10,
+     * Project[[salary{f}#23, emp_no{f}#18 AS emp_no2#7, $$emp_no$temp_name$29{r}#30 AS emp_no#10,
      *  emp_no{f}#18 AS emp_no3#13, salary3{r}#16]]
      * \_Eval[[salary{f}#23 * 2[INTEGER] AS $$emp_no$temp_name$29#30, $$emp_no$temp_name$29{r$}#30 * 2[INTEGER] AS salary3#16]]
      *   \_Limit[1000[INTEGER],false,false]
@@ -303,7 +303,7 @@ public void testNonAliasShadowingAliasedAttributeWithAgg() {
 
     /**
      * 
{@code
-     * EsqlProject[[salary{f}#35, emp_no{f}#30 AS emp_no2#22, $$id$temp_name$41{r$}#42 AS emp_no#25, emp_no{f}#30 AS emp_no3#28,
+     * Project[[salary{f}#35, emp_no{f}#30 AS emp_no2#22, $$id$temp_name$41{r$}#42 AS emp_no#25, emp_no{f}#30 AS emp_no3#28,
      *  salary3{r}#19]]
      * \_Eval[[salary{f}#35 * 2[INTEGER] AS $$id$temp_name$41#42, $$id$temp_name$41{r$}#42 * 2[INTEGER] AS salary3#19]]
      *   \_Limit[1000[INTEGER],false,false]
@@ -349,7 +349,7 @@ public void testNonAliasShadowingAliasedAttributeWithRename() {
 
     /**
      * 
{@code
-     * EsqlProject[[emp_no{f}#18, salary{f}#23, emp_no{f}#18 AS emp_no3#10, emp_no2{r}#13, salary3{r}#16]]
+     * Project[[emp_no{f}#18, salary{f}#23, emp_no{f}#18 AS emp_no3#10, emp_no2{r}#13, salary3{r}#16]]
      * \_Eval[[salary{f}#23 * 2[INTEGER] AS emp_no2#13, emp_no2{r}#13 * 3[INTEGER] AS salary3#16]]
      *   \_Limit[1000[INTEGER],false,false]
      *     \_EsRelation[test][_meta_field{f}#24, emp_no{f}#18, first_name{f}#19, ..]
@@ -385,7 +385,7 @@ public void testNonAliasShadowingAliasOfAliasedAttribute() {
 
     /**
      * 
{@code
-     * EsqlProject[[emp_no{f}#24, salary{f}#29, emp_no{f}#24 AS emp_no3#13, salary{f}#29 AS salary3#16,
+     * Project[[emp_no{f}#24, salary{f}#29, emp_no{f}#24 AS emp_no3#13, salary{f}#29 AS salary3#16,
      *  salary{f}#29 AS emp_no2#19, emp_no{f}#24 AS salary2#22]]
      * \_Limit[1000[INTEGER],false,false]
      *   \_EsRelation[test][_meta_field{f}#30, emp_no{f}#24, first_name{f}#25, ..]
@@ -417,7 +417,7 @@ public void testAliasShadowingOtherAlias() {
 
     /**
      * 
{@code
-     * EsqlProject[[salary{f}#22, salary2{r}#6, salary2{r}#6 AS aliased_salary2#9, salary3{r}#12, salary2{r}#6 AS twice_aliased_salary2#15]]
+     * Project[[salary{f}#22, salary2{r}#6, salary2{r}#6 AS aliased_salary2#9, salary3{r}#12, salary2{r}#6 AS twice_aliased_salary2#15]]
      * \_Eval[[salary{f}#22 * 2[INTEGER] AS salary2#6, salary2{r}#6 * 3[INTEGER] AS salary3#12]]
      *   \_Limit[1000[INTEGER],false,false]
      *     \_EsRelation[test][_meta_field{f}#23, emp_no{f}#17, first_name{f}#18, ..]
@@ -452,7 +452,7 @@ public void testAliasForNonAlias() {
 
     /**
      * 
{@code
-     * EsqlProject[[salary{f}#25, salary2{r}#6 AS aliased_salary2#9, $$salary2$temp_name$31{r$}#32 AS salary2#12, salary3{r}#15,
+     * Project[[salary{f}#25, salary2{r}#6 AS aliased_salary2#9, $$salary2$temp_name$31{r$}#32 AS salary2#12, salary3{r}#15,
      *  salary3{r}#15 AS salary4#18]]
      * \_Eval[[salary{f}#25 * 2[INTEGER] AS salary2#6, salary2{r}#6 * 3[INTEGER] AS $$salary2$temp_name$31#32,
      *  $$salary2$temp_name$31{r$}#32 * 4[INTEGER] AS salary3#15]]
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
index c6ff818246e38..dac060dca0617 100644
--- 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
@@ -24,7 +24,6 @@
 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;
@@ -473,7 +472,7 @@ public void testReplaceInlineStatsFilteredAggWithEvalSingleAggWithExpression() {
     /*
      * Limit[1000[INTEGER],false]
      * \_InlineJoin[LEFT,[emp_no{f}#9],[emp_no{f}#9],[emp_no{r}#9]]
-     *   |_EsqlProject[[salary{f}#14, emp_no{f}#9]]
+     *   |_Project[[salary{f}#14, emp_no{f}#9]]
      *   | \_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]]
@@ -494,7 +493,7 @@ public void testReplaceInlineStatsFilteredAggWithEvalMixedFilterAndNoFilter() {
         var plan = plan(query);
         var limit = as(plan, Limit.class);
         var ij = as(limit.child(), InlineJoin.class);
-        var left = as(ij.left(), EsqlProject.class);
+        var left = as(ij.left(), Project.class);
         assertThat(Expressions.names(left.projections()), contains("salary", "emp_no"));
         var relation = as(left.child(), EsRelation.class);
         var right = as(ij.right(), Project.class);
@@ -525,7 +524,7 @@ public void testReplaceInlineStatsFilteredAggWithEvalMixedFilterAndNoFilter() {
     /**
      * Limit[1000[INTEGER],true]
      * \_InlineJoin[LEFT,[],[],[]]
-     *   |_EsqlProject[[salary{f}#16]]
+     *   |_Project[[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
@@ -584,7 +583,7 @@ public void testReplaceInlineStatsFilteredAggWithEvalFilterFalseAndNull() {
     }
 
     /**
-     * EsqlProject[[emp_no{f}#6, salary{f}#11, count(salary) where not true{r}#5]]
+     * Project[[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..]
@@ -599,7 +598,7 @@ public void testReplaceInlineStatsFilteredAggWithEvalNotTrue() {
             return;
         }
         var plan = plan(query);
-        var project = as(plan, EsqlProject.class);
+        var project = as(plan, Project.class);
         assertThat(Expressions.names(project.projections()), contains("emp_no", "salary", "count(salary) where not true"));
 
         var eval = as(project.child(), Eval.class);
@@ -616,7 +615,7 @@ public void testReplaceInlineStatsFilteredAggWithEvalNotTrue() {
     /*
      * Limit[1000[INTEGER],true]
      * \_InlineJoin[LEFT,[],[],[]]
-     *   |_EsqlProject[[emp_no{f}#8, salary{f}#13, gender{f}#10]]
+     *   |_Project[[emp_no{f}#8, salary{f}#13, gender{f}#10]]
      *   | \_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]]
@@ -634,7 +633,7 @@ public void testReplaceInlineStatsFilteredAggWithEvalNotFalse() {
         var limit = as(plan, Limit.class);
         var ij = as(limit.child(), InlineJoin.class);
 
-        var left = as(ij.left(), EsqlProject.class);
+        var left = as(ij.left(), Project.class);
         assertThat(Expressions.names(left.projections()), contains("emp_no", "salary", "gender"));
         var relation = as(left.child(), EsRelation.class);
 
@@ -649,7 +648,7 @@ public void testReplaceInlineStatsFilteredAggWithEvalNotFalse() {
     }
 
     /**
-     * EsqlProject[[salary{f}#10, count(salary) where false{r}#4]]
+     * Project[[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..]
@@ -664,7 +663,7 @@ public void testReplaceInlineStatsFilteredAggWithEvalCount() {
             return;
         }
         var plan = plan(query);
-        var project = as(plan, EsqlProject.class);
+        var project = as(plan, Project.class);
         assertThat(Expressions.names(project.projections()), contains("salary", "count(salary) where false"));
 
         var eval = as(project.child(), Eval.class);
@@ -679,7 +678,7 @@ public void testReplaceInlineStatsFilteredAggWithEvalCount() {
     }
 
     /**
-     * EsqlProject[[salary{f}#10, count_distinct(salary   2)   3 where false{r}#4]]
+     * Project[[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..]
@@ -694,7 +693,7 @@ public void testReplaceInlineStatsFilteredAggWithEvalCountDistinctInExpression()
             return;
         }
         var plan = plan(query);
-        var project = as(plan, EsqlProject.class);
+        var project = as(plan, Project.class);
         assertThat(Expressions.names(project.projections()), contains("salary", "count_distinct(salary + 2) + 3 where false"));
 
         var eval = as(project.child(), Eval.class);
@@ -711,7 +710,7 @@ public void testReplaceInlineStatsFilteredAggWithEvalCountDistinctInExpression()
     /*
      * 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]]
+     *   |_Project[[emp_no{f}#17, salary{f}#22]]
      *   | \_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]]
@@ -734,7 +733,7 @@ public void testReplaceInlineStatsFilteredAggWithEvalSameAggWithAndWithoutFilter
         var limit = as(plan, Limit.class);
         var ij = as(limit.child(), InlineJoin.class);
 
-        var left = as(ij.left(), EsqlProject.class);
+        var left = as(ij.left(), Project.class);
         assertThat(Expressions.names(left.projections()), contains("emp_no", "salary"));
         var relation = as(left.child(), EsRelation.class);
 
@@ -764,7 +763,7 @@ public void testReplaceInlineStatsFilteredAggWithEvalSameAggWithAndWithoutFilter
     }
 
     /*
-     * EsqlProject[[emp_no{f}#9, count{r}#5, cc{r}#8]]
+     * Project[[emp_no{f}#9, count{r}#5, cc{r}#8]]
      * \_TopN[[Order[emp_no{f}#9,ASC,LAST]],3[INTEGER]]
      *   \_Eval[[0[LONG] AS count#5, 0[LONG] AS cc#8]]
      *     \_EsRelation[test][_meta_field{f}#15, emp_no{f}#9, first_name{f}#10, g..]
@@ -782,7 +781,7 @@ public void testReplaceTwoConsecutiveInlineStats_WithFalseFilters() {
             return;
         }
         var plan = plan(query);
-        var project = as(plan, EsqlProject.class);
+        var project = as(plan, Project.class);
         assertThat(Expressions.names(project.projections()), contains("emp_no", "count", "cc"));
 
         var topN = as(project.child(), TopN.class);
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/plan/logical/local/EsqlProjectSerializationTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/plan/logical/local/EsqlProjectSerializationTests.java
deleted file mode 100644
index 7e5e368fff77f..0000000000000
--- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/plan/logical/local/EsqlProjectSerializationTests.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * 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.plan.logical.local;
-
-import org.elasticsearch.xpack.esql.core.expression.Attribute;
-import org.elasticsearch.xpack.esql.core.expression.NamedExpression;
-import org.elasticsearch.xpack.esql.plan.logical.AbstractLogicalPlanSerializationTests;
-import org.elasticsearch.xpack.esql.plan.logical.LogicalPlan;
-
-import java.io.IOException;
-import java.util.List;
-
-public class EsqlProjectSerializationTests extends AbstractLogicalPlanSerializationTests {
-    @Override
-    protected EsqlProject createTestInstance() {
-        LogicalPlan child = randomChild(0);
-        List projections = randomFieldAttributes(1, 10, false);
-        return new EsqlProject(randomSource(), child, projections);
-    }
-
-    @Override
-    protected EsqlProject mutateInstance(EsqlProject instance) throws IOException {
-        LogicalPlan child = instance.child();
-        List projections = instance.projections();
-        if (randomBoolean()) {
-            child = randomValueOtherThan(child, () -> randomChild(0));
-        } else {
-            projections = randomValueOtherThan(projections, () -> randomFieldAttributes(1, 10, false));
-        }
-        return new EsqlProject(instance.source(), child, projections);
-    }
-
-    @Override
-    protected boolean alwaysEmptySource() {
-        return true;
-    }
-}