From 0c58bf7686f841bd09d7650a0e63630ec58162a7 Mon Sep 17 00:00:00 2001 From: Felix Barnsteiner Date: Fri, 20 Feb 2026 09:59:24 +0100 Subject: [PATCH 1/9] Add TimestampBoundsAware analysis mechanism Introduce timestamp-bounds-aware analysis plumbing and use it to inject filter-derived bounds into PromqlCommand range queries during analysis. --- .../xpack/esql/EsqlTestUtils.java | 27 +++++++++- .../esql/analysis/MutableAnalyzerContext.java | 21 +++++++- .../xpack/esql/analysis/Analyzer.java | 37 +++++++++++++ .../xpack/esql/analysis/AnalyzerContext.java | 52 ++++++++++++++++++- .../xpack/esql/analysis/Verifier.java | 16 ++++++ .../function/TimestampBoundsAware.java | 41 +++++++++++++++ .../plan/logical/promql/PromqlCommand.java | 21 +++++++- .../xpack/esql/session/EsqlSession.java | 27 +++++----- .../esql/analysis/AnalyzerTestUtils.java | 29 ++++++++++- .../analysis/promql/PromqlVerifierTests.java | 12 +++++ 10 files changed, 262 insertions(+), 21 deletions(-) create mode 100644 x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/TimestampBoundsAware.java diff --git a/x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/EsqlTestUtils.java b/x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/EsqlTestUtils.java index d9e18ba7ed7af..d9e749f1349d7 100644 --- a/x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/EsqlTestUtils.java +++ b/x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/EsqlTestUtils.java @@ -45,6 +45,7 @@ import org.elasticsearch.compute.data.LongRangeBlockBuilder; import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.data.TDigestHolder; +import org.elasticsearch.core.Nullable; import org.elasticsearch.core.PathUtils; import org.elasticsearch.core.SuppressForbidden; import org.elasticsearch.core.Tuple; @@ -85,6 +86,7 @@ import org.elasticsearch.xpack.esql.analysis.UnmappedResolution; import org.elasticsearch.xpack.esql.analysis.Verifier; import org.elasticsearch.xpack.esql.core.expression.Alias; +import org.elasticsearch.xpack.esql.core.querydsl.QueryDslTimestampBoundsExtractor.TimestampBounds; import org.elasticsearch.xpack.esql.core.expression.Attribute; import org.elasticsearch.xpack.esql.core.expression.Expression; import org.elasticsearch.xpack.esql.core.expression.FieldAttribute; @@ -569,6 +571,28 @@ public static MutableAnalyzerContext testAnalyzerContext( EnrichResolution enrichResolution, InferenceResolution inferenceResolution, UnmappedResolution unmappedResolution + ) { + return testAnalyzerContext( + configuration, + functionRegistry, + indexResolutions, + lookupResolution, + enrichResolution, + inferenceResolution, + unmappedResolution, + null + ); + } + + public static MutableAnalyzerContext testAnalyzerContext( + Configuration configuration, + EsqlFunctionRegistry functionRegistry, + Map indexResolutions, + Map lookupResolution, + EnrichResolution enrichResolution, + InferenceResolution inferenceResolution, + UnmappedResolution unmappedResolution, + @Nullable TimestampBounds timestampBounds ) { return new MutableAnalyzerContext( configuration, @@ -578,7 +602,8 @@ public static MutableAnalyzerContext testAnalyzerContext( enrichResolution, inferenceResolution, randomMinimumVersion(), - unmappedResolution + unmappedResolution, + timestampBounds ); } diff --git a/x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/analysis/MutableAnalyzerContext.java b/x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/analysis/MutableAnalyzerContext.java index e75956ce3ad79..d0d79d5b4b930 100644 --- a/x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/analysis/MutableAnalyzerContext.java +++ b/x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/analysis/MutableAnalyzerContext.java @@ -8,7 +8,9 @@ package org.elasticsearch.xpack.esql.analysis; import org.elasticsearch.TransportVersion; +import org.elasticsearch.core.Nullable; import org.elasticsearch.test.TransportVersionUtils; +import org.elasticsearch.xpack.esql.core.querydsl.QueryDslTimestampBoundsExtractor.TimestampBounds; import org.elasticsearch.xpack.esql.expression.function.EsqlFunctionRegistry; import org.elasticsearch.xpack.esql.index.IndexResolution; import org.elasticsearch.xpack.esql.inference.InferenceResolution; @@ -33,16 +35,33 @@ public MutableAnalyzerContext( InferenceResolution inferenceResolution, TransportVersion minimumVersion, UnmappedResolution unmappedResolution + ) { + this(configuration, functionRegistry, indexResolution, lookupResolution, enrichResolution, inferenceResolution, + minimumVersion, unmappedResolution, null); + } + + public MutableAnalyzerContext( + Configuration configuration, + EsqlFunctionRegistry functionRegistry, + Map indexResolution, + Map lookupResolution, + EnrichResolution enrichResolution, + InferenceResolution inferenceResolution, + TransportVersion minimumVersion, + UnmappedResolution unmappedResolution, + @Nullable TimestampBounds timestampBounds ) { super( configuration, functionRegistry, + null, indexResolution, lookupResolution, enrichResolution, inferenceResolution, minimumVersion, - unmappedResolution + unmappedResolution, + timestampBounds ); this.currentVersion = minimumVersion; } 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 97b4f470e598b..e22b268bd9108 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 @@ -65,6 +65,7 @@ import org.elasticsearch.xpack.esql.expression.function.AggregateMetricDoubleNativeSupport; import org.elasticsearch.xpack.esql.expression.function.EsqlFunctionRegistry; import org.elasticsearch.xpack.esql.expression.function.FunctionDefinition; +import org.elasticsearch.xpack.esql.expression.function.TimestampBoundsAware; import org.elasticsearch.xpack.esql.expression.function.UnresolvedFunction; import org.elasticsearch.xpack.esql.expression.function.UnsupportedAttribute; import org.elasticsearch.xpack.esql.expression.function.aggregate.Absent; @@ -225,6 +226,7 @@ public class Analyzer extends ParameterizedRuleExecutor { + + @Override + protected boolean skipResolved() { + return false; + } + + @Override + protected LogicalPlan rule(LogicalPlan plan, AnalyzerContext context) { + var bounds = context.timestampBounds(); + if (bounds == null) { + return plan; + } + if (plan instanceof TimestampBoundsAware tba && tba.needsTimestampBounds()) { + @SuppressWarnings("unchecked") + var planAware = (TimestampBoundsAware) tba; + plan = planAware.withTimestampBounds( + Literal.dateTime(plan.source(), bounds.start()), + Literal.dateTime(plan.source(), bounds.end()) + ); + } + return plan.transformExpressionsUp(Expression.class, expression -> { + if (expression instanceof TimestampBoundsAware tba && tba.needsTimestampBounds()) { + @SuppressWarnings("unchecked") + var exprAware = (TimestampBoundsAware) tba; + return exprAware.withTimestampBounds( + Literal.dateTime(expression.source(), bounds.start()), + Literal.dateTime(expression.source(), bounds.end()) + ); + } + return expression; + }); + } + } + private static class ResolveFunctions extends ParameterizedAnalyzerRule { @Override diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/analysis/AnalyzerContext.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/analysis/AnalyzerContext.java index 86c7501547d6c..27a9fd4aec1c4 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/analysis/AnalyzerContext.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/analysis/AnalyzerContext.java @@ -10,7 +10,9 @@ import org.elasticsearch.TransportVersion; import org.elasticsearch.cluster.metadata.Metadata; import org.elasticsearch.cluster.metadata.ProjectMetadata; +import org.elasticsearch.core.Nullable; import org.elasticsearch.xpack.esql.core.expression.MetadataAttribute; +import org.elasticsearch.xpack.esql.core.querydsl.QueryDslTimestampBoundsExtractor.TimestampBounds; import org.elasticsearch.xpack.esql.expression.function.EsqlFunctionRegistry; import org.elasticsearch.xpack.esql.index.IndexResolution; import org.elasticsearch.xpack.esql.inference.InferenceResolution; @@ -34,6 +36,7 @@ public class AnalyzerContext { private final ProjectMetadata projectMetadata; private Boolean hasRemoteIndices; private final UnmappedResolution unmappedResolution; + private final TimestampBounds timestampBounds; public AnalyzerContext( Configuration configuration, @@ -45,6 +48,32 @@ public AnalyzerContext( InferenceResolution inferenceResolution, TransportVersion minimumVersion, UnmappedResolution unmappedResolution + ) { + this( + configuration, + functionRegistry, + projectMetadata, + indexResolution, + lookupResolution, + enrichResolution, + inferenceResolution, + minimumVersion, + unmappedResolution, + null + ); + } + + public AnalyzerContext( + Configuration configuration, + EsqlFunctionRegistry functionRegistry, + ProjectMetadata projectMetadata, + Map indexResolution, + Map lookupResolution, + EnrichResolution enrichResolution, + InferenceResolution inferenceResolution, + TransportVersion minimumVersion, + UnmappedResolution unmappedResolution, + @Nullable TimestampBounds timestampBounds ) { this.configuration = configuration; this.functionRegistry = functionRegistry; @@ -55,6 +84,7 @@ public AnalyzerContext( this.inferenceResolution = inferenceResolution; this.minimumVersion = minimumVersion; this.unmappedResolution = unmappedResolution; + this.timestampBounds = timestampBounds; assert minimumVersion != null : "AnalyzerContext must have a minimum transport version"; assert TransportVersion.current().supports(minimumVersion) @@ -129,6 +159,14 @@ public UnmappedResolution unmappedResolution() { return unmappedResolution; } + /** + * Returns the {@code @timestamp} bounds extracted from the query DSL filter, or {@code null} if not available. + */ + @Nullable + public TimestampBounds timestampBounds() { + return timestampBounds; + } + public Set allowedTags() { Set result = new HashSet<>(); result.addAll(MetadataAttribute.ATTRIBUTES_MAP.keySet()); @@ -155,6 +193,17 @@ public AnalyzerContext( UnmappedResolution unmappedResolution, ProjectMetadata projectMetadata, EsqlSession.PreAnalysisResult result + ) { + this(configuration, functionRegistry, unmappedResolution, projectMetadata, result, null); + } + + public AnalyzerContext( + Configuration configuration, + EsqlFunctionRegistry functionRegistry, + UnmappedResolution unmappedResolution, + ProjectMetadata projectMetadata, + EsqlSession.PreAnalysisResult result, + @Nullable TimestampBounds timestampBounds ) { this( configuration, @@ -165,7 +214,8 @@ public AnalyzerContext( result.enrichResolution(), result.inferenceResolution(), result.minimumTransportVersion(), - unmappedResolution + unmappedResolution, + timestampBounds ); } } 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 c21d72b71e8bd..00dcaaebbd24e 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 @@ -24,6 +24,7 @@ import org.elasticsearch.xpack.esql.core.tree.Node; import org.elasticsearch.xpack.esql.core.type.DataType; import org.elasticsearch.xpack.esql.core.util.Holder; +import org.elasticsearch.xpack.esql.expression.function.TimestampBoundsAware; import org.elasticsearch.xpack.esql.expression.function.UnsupportedAttribute; import org.elasticsearch.xpack.esql.expression.predicate.operator.arithmetic.Neg; import org.elasticsearch.xpack.esql.expression.predicate.operator.comparison.Equals; @@ -95,6 +96,7 @@ Collection verify(LogicalPlan plan, BitSet partialMetrics) { checkUnresolvedAttributes(plan, failures); ConfigurationAware.verifyNoMarkerConfiguration(plan, failures); + checkUnresolvedTimestampBounds(plan, failures); // in case of failures bail-out as all other checks will be redundant if (failures.hasFailures()) { @@ -220,6 +222,20 @@ else if (p instanceof PromqlCommand promql) { }); } + private static void checkUnresolvedTimestampBounds(LogicalPlan plan, Failures failures) { + plan.forEachDown(p -> p.forEachExpression(Expression.class, e -> { + if (e instanceof TimestampBoundsAware tba && tba.needsTimestampBounds()) { + failures.add( + fail( + e, + "[{}] requires a time range; provide explicit from/to parameters or add a @timestamp range to the query filter", + e.sourceText() + ) + ); + } + })); + } + /** * Build a list of checkers based on the components in the plan. */ diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/TimestampBoundsAware.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/TimestampBoundsAware.java new file mode 100644 index 0000000000000..dcb307b9cc071 --- /dev/null +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/TimestampBoundsAware.java @@ -0,0 +1,41 @@ +/* + * 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.expression.function; + +import org.elasticsearch.xpack.esql.analysis.Analyzer; +import org.elasticsearch.xpack.esql.analysis.Verifier; +import org.elasticsearch.xpack.esql.capabilities.ConfigurationAware; +import org.elasticsearch.xpack.esql.capabilities.PostAnalysisVerificationAware; +import org.elasticsearch.xpack.esql.core.expression.Literal; + +/** + * Marker interface for nodes (expressions or plans) that require {@code @timestamp} bounds derived from the query DSL filter. + *

+ * Implementations are resolved during analysis by {@link Analyzer}'s {@code ResolveTimestampBoundsAware} rule, + * following the same pattern as {@link ConfigurationAware}. + *

+ *

+ * Expression implementations that still {@link #needsTimestampBounds() need bounds} after analysis are automatically + * rejected by the {@link Verifier} with a client error. + * LogicalPlan implementations are responsible for their own validation via {@link PostAnalysisVerificationAware#postAnalysisVerification}. + *

+ * + * @param the type returned by {@link #withTimestampBounds}, typically {@code Expression} or {@code LogicalPlan} + */ +public interface TimestampBoundsAware { + + /** + * Returns {@code true} if this node still needs timestamp bounds to be injected. + */ + boolean needsTimestampBounds(); + + /** + * Returns a copy of this node with the given timestamp bounds applied. + */ + T withTimestampBounds(Literal start, Literal end); +} diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/promql/PromqlCommand.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/promql/PromqlCommand.java index 560639854f7da..1a987143c8f05 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/promql/PromqlCommand.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/promql/PromqlCommand.java @@ -23,6 +23,7 @@ import org.elasticsearch.xpack.esql.core.type.DataType; import org.elasticsearch.xpack.esql.core.util.Holder; import org.elasticsearch.xpack.esql.expression.function.TimestampAware; +import org.elasticsearch.xpack.esql.expression.function.TimestampBoundsAware; import org.elasticsearch.xpack.esql.plan.logical.LogicalPlan; import org.elasticsearch.xpack.esql.plan.logical.UnaryPlan; import org.elasticsearch.xpack.esql.plan.logical.promql.operator.VectorBinaryComparison; @@ -44,7 +45,12 @@ * Container plan for embedded PromQL queries. * Gets eliminated by the analyzer once the query is validated. */ -public class PromqlCommand extends UnaryPlan implements TelemetryAware, PostAnalysisVerificationAware, TimestampAware { +public class PromqlCommand extends UnaryPlan + implements + TelemetryAware, + PostAnalysisVerificationAware, + TimestampAware, + TimestampBoundsAware { /** * The name of the column containing the step value (aka time bucket) in range queries. @@ -162,7 +168,18 @@ public PromqlCommand withPromqlPlan(LogicalPlan newPromqlPlan) { ); } - public PromqlCommand withStartEnd(Literal start, Literal end) { + /** + * Bounds are only needed when {@code buckets} is specified without an explicit time range. + * When {@code step} alone is set, the query can proceed without start/end because the step + * directly defines the bucket size; {@link #postAnalysisVerification} validates that case. + */ + @Override + public boolean needsTimestampBounds() { + return buckets.value() != null && hasTimeRange() == false; + } + + @Override + public LogicalPlan withTimestampBounds(Literal start, Literal end) { return new PromqlCommand( source(), child(), diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java index 0f38d4e2d875d..f923b0b402036 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java @@ -54,7 +54,6 @@ import org.elasticsearch.xpack.esql.approximation.Approximation; import org.elasticsearch.xpack.esql.core.expression.Attribute; import org.elasticsearch.xpack.esql.core.expression.FoldContext; -import org.elasticsearch.xpack.esql.core.expression.Literal; import org.elasticsearch.xpack.esql.core.expression.ReferenceAttribute; import org.elasticsearch.xpack.esql.core.querydsl.QueryDslTimestampBoundsExtractor; import org.elasticsearch.xpack.esql.core.tree.NodeUtils; @@ -82,7 +81,6 @@ import org.elasticsearch.xpack.esql.plan.logical.join.InlineJoin; 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; import org.elasticsearch.xpack.esql.plan.physical.EstimatesRowSize; import org.elasticsearch.xpack.esql.plan.physical.LocalSourceExec; import org.elasticsearch.xpack.esql.plan.physical.PhysicalPlan; @@ -277,16 +275,6 @@ public void execute( explainMode = true; plan = explain.query(); parsedPlanString = plan.toString(); - } else if (plan instanceof PromqlCommand promqlCommand && promqlCommand.isRangeQuery() && promqlCommand.hasTimeRange() == false) { - // infer start/end from filter if not explicitly set - QueryDslTimestampBoundsExtractor.TimestampBounds bounds = QueryDslTimestampBoundsExtractor.extractTimestampBounds( - request.filter() - ); - if (bounds != null) { - Literal startLiteral = Literal.dateTime(promqlCommand.source(), bounds.start()); - Literal endLiteral = Literal.dateTime(promqlCommand.source(), bounds.end()); - plan = promqlCommand.withStartEnd(startLiteral, endLiteral); - } } final EsqlStatement statementFinal = statement; @@ -1165,7 +1153,7 @@ private void analyzeWithRetry( } TimeSpanMarker analysisProfile = executionInfo.queryProfile().analysis(); analysisProfile.start(); - LogicalPlan plan = analyzedPlan(parsed, unmappedResolution, configuration, result, executionInfo); + LogicalPlan plan = analyzedPlan(parsed, unmappedResolution, configuration, result, executionInfo, requestFilter); analysisProfile.stop(); LOGGER.debug("Analyzed plan ({}):\n{}", description, plan); // the analysis succeeded from the first attempt, irrespective if it had a filter or not, just continue with the planning @@ -1211,10 +1199,19 @@ private LogicalPlan analyzedPlan( UnmappedResolution unmappedResolution, Configuration configuration, PreAnalysisResult r, - EsqlExecutionInfo executionInfo + EsqlExecutionInfo executionInfo, + QueryBuilder requestFilter ) throws Exception { handleFieldCapsFailures(configuration.allowPartialResults(), executionInfo, r.indexResolution()); - AnalyzerContext analyzerContext = new AnalyzerContext(configuration, functionRegistry, unmappedResolution, projectMetadata, r); + var timestampBounds = QueryDslTimestampBoundsExtractor.extractTimestampBounds(requestFilter); + AnalyzerContext analyzerContext = new AnalyzerContext( + configuration, + functionRegistry, + unmappedResolution, + projectMetadata, + r, + timestampBounds + ); Analyzer analyzer = new Analyzer(analyzerContext, verifier); LogicalPlan plan = analyzer.analyze(parsed); plan.setAnalyzed(); diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/AnalyzerTestUtils.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/AnalyzerTestUtils.java index e3383412e9027..49b4d8d7dd3a2 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/AnalyzerTestUtils.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/AnalyzerTestUtils.java @@ -14,6 +14,7 @@ import org.elasticsearch.test.ESTestCase; import org.elasticsearch.xpack.core.enrich.EnrichPolicy; import org.elasticsearch.xpack.esql.EsqlTestUtils; +import org.elasticsearch.xpack.esql.core.querydsl.QueryDslTimestampBoundsExtractor.TimestampBounds; import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.core.type.EsField; import org.elasticsearch.xpack.esql.core.type.InvalidMappedField; @@ -70,6 +71,19 @@ public static Analyzer analyzer(IndexResolution indexResolution) { return analyzer(indexResolution, TEST_VERIFIER); } + /** Analyzer with a single index and {@code @timestamp} bounds from a query DSL filter. */ + public static Analyzer analyzer(IndexResolution indexResolution, TimestampBounds timestampBounds) { + return analyzer( + indexResolutions(indexResolution), + defaultLookupResolution(), + defaultEnrichResolution(), + TEST_VERIFIER, + TEST_CFG, + UNMAPPED_FIELDS.defaultValue(), + timestampBounds + ); + } + /** Simple analyzer with multiple indexes, which may also be invalid */ public static Analyzer analyzer(Map indexResolutions) { return analyzer(indexResolutions, defaultLookupResolution(), defaultEnrichResolution(), TEST_VERIFIER, TEST_CFG); @@ -113,6 +127,18 @@ public static Analyzer analyzer( Verifier verifier, Configuration config, UnmappedResolution unmappedResolution + ) { + return analyzer(indexResolutions, lookupResolution, enrichResolution, verifier, config, unmappedResolution, null); + } + + public static Analyzer analyzer( + Map indexResolutions, + Map lookupResolution, + EnrichResolution enrichResolution, + Verifier verifier, + Configuration config, + UnmappedResolution unmappedResolution, + @Nullable TimestampBounds timestampBounds ) { return new Analyzer( testAnalyzerContext( @@ -122,7 +148,8 @@ public static Analyzer analyzer( lookupResolution, enrichResolution, defaultInferenceResolution(), - unmappedResolution + unmappedResolution, + timestampBounds ), verifier ); diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/promql/PromqlVerifierTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/promql/PromqlVerifierTests.java index af59fca3f74d6..d0a871a562ccc 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/promql/PromqlVerifierTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/promql/PromqlVerifierTests.java @@ -10,7 +10,11 @@ import org.elasticsearch.test.ESTestCase; import org.elasticsearch.xpack.esql.analysis.Analyzer; import org.elasticsearch.xpack.esql.analysis.AnalyzerTestUtils; +import org.elasticsearch.xpack.esql.core.querydsl.QueryDslTimestampBoundsExtractor.TimestampBounds; +import org.elasticsearch.xpack.esql.parser.EsqlParser; +import java.time.Instant; +import java.time.temporal.ChronoUnit; import java.util.List; import static org.elasticsearch.xpack.esql.EsqlTestUtils.withDefaultLimitWarning; @@ -113,6 +117,14 @@ public void testPromqlBucketsWithoutRange() { ); } + public void testPromqlBucketsWithTimestampBoundsFromContext() { + var now = Instant.now(); + var bounds = new TimestampBounds(now.minus(1, ChronoUnit.HOURS), now); + var analyzer = AnalyzerTestUtils.analyzer(AnalyzerTestUtils.tsdbIndexResolution(), bounds); + var plan = analyzer.analyze(EsqlParser.INSTANCE.parseQuery("PROMQL index=test buckets=10 avg(network.bytes_in)")); + assertTrue("Plan should be resolved after timestamp bounds injection", plan.resolved()); + } + public void testNoMetricNameMatcherNotSupported() { assertThat( error("PROMQL index=test step=5m {foo=\"bar\"}", tsdb), From 8f4eb61dea7732fa8a3a75243210084088db2bc2 Mon Sep 17 00:00:00 2001 From: Felix Barnsteiner Date: Fri, 20 Feb 2026 12:30:02 +0100 Subject: [PATCH 2/9] Fix post merge compile error --- .../org/elasticsearch/xpack/esql/analysis/AnalyzerContext.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/analysis/AnalyzerContext.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/analysis/AnalyzerContext.java index 56b1c2df407c1..f72611fad4664 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/analysis/AnalyzerContext.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/analysis/AnalyzerContext.java @@ -60,6 +60,7 @@ public AnalyzerContext( lookupResolution, enrichResolution, inferenceResolution, + externalSourceResolution, minimumVersion, unmappedResolution, null @@ -74,6 +75,7 @@ public AnalyzerContext( Map lookupResolution, EnrichResolution enrichResolution, InferenceResolution inferenceResolution, + ExternalSourceResolution externalSourceResolution, TransportVersion minimumVersion, UnmappedResolution unmappedResolution, @Nullable TimestampBounds timestampBounds From 6c3ddd987523bebad0562da662a9f5cb9c773d08 Mon Sep 17 00:00:00 2001 From: elasticsearchmachine Date: Fri, 20 Feb 2026 11:36:38 +0000 Subject: [PATCH 3/9] [CI] Auto commit changes from spotless --- .../org/elasticsearch/xpack/esql/EsqlTestUtils.java | 2 +- .../xpack/esql/analysis/MutableAnalyzerContext.java | 13 +++++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/EsqlTestUtils.java b/x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/EsqlTestUtils.java index d9e749f1349d7..f55a15de9d902 100644 --- a/x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/EsqlTestUtils.java +++ b/x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/EsqlTestUtils.java @@ -86,7 +86,6 @@ import org.elasticsearch.xpack.esql.analysis.UnmappedResolution; import org.elasticsearch.xpack.esql.analysis.Verifier; import org.elasticsearch.xpack.esql.core.expression.Alias; -import org.elasticsearch.xpack.esql.core.querydsl.QueryDslTimestampBoundsExtractor.TimestampBounds; import org.elasticsearch.xpack.esql.core.expression.Attribute; import org.elasticsearch.xpack.esql.core.expression.Expression; import org.elasticsearch.xpack.esql.core.expression.FieldAttribute; @@ -98,6 +97,7 @@ import org.elasticsearch.xpack.esql.core.expression.ReferenceAttribute; import org.elasticsearch.xpack.esql.core.expression.predicate.regex.RLikePattern; import org.elasticsearch.xpack.esql.core.expression.predicate.regex.WildcardPattern; +import org.elasticsearch.xpack.esql.core.querydsl.QueryDslTimestampBoundsExtractor.TimestampBounds; import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.core.type.DataType; import org.elasticsearch.xpack.esql.core.type.EsField; diff --git a/x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/analysis/MutableAnalyzerContext.java b/x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/analysis/MutableAnalyzerContext.java index d0d79d5b4b930..f6e8fcfd2e374 100644 --- a/x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/analysis/MutableAnalyzerContext.java +++ b/x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/analysis/MutableAnalyzerContext.java @@ -36,8 +36,17 @@ public MutableAnalyzerContext( TransportVersion minimumVersion, UnmappedResolution unmappedResolution ) { - this(configuration, functionRegistry, indexResolution, lookupResolution, enrichResolution, inferenceResolution, - minimumVersion, unmappedResolution, null); + this( + configuration, + functionRegistry, + indexResolution, + lookupResolution, + enrichResolution, + inferenceResolution, + minimumVersion, + unmappedResolution, + null + ); } public MutableAnalyzerContext( From 2fb27a8bbec721fcf747cfe8a40285bf67c12097 Mon Sep 17 00:00:00 2001 From: Felix Barnsteiner Date: Fri, 20 Feb 2026 13:56:15 +0100 Subject: [PATCH 4/9] Fix compile error --- .../xpack/esql/analysis/MutableAnalyzerContext.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/analysis/MutableAnalyzerContext.java b/x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/analysis/MutableAnalyzerContext.java index f6e8fcfd2e374..560e2eaa3d50f 100644 --- a/x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/analysis/MutableAnalyzerContext.java +++ b/x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/analysis/MutableAnalyzerContext.java @@ -11,6 +11,7 @@ import org.elasticsearch.core.Nullable; import org.elasticsearch.test.TransportVersionUtils; import org.elasticsearch.xpack.esql.core.querydsl.QueryDslTimestampBoundsExtractor.TimestampBounds; +import org.elasticsearch.xpack.esql.datasources.ExternalSourceResolution; import org.elasticsearch.xpack.esql.expression.function.EsqlFunctionRegistry; import org.elasticsearch.xpack.esql.index.IndexResolution; import org.elasticsearch.xpack.esql.inference.InferenceResolution; @@ -68,6 +69,7 @@ public MutableAnalyzerContext( lookupResolution, enrichResolution, inferenceResolution, + ExternalSourceResolution.EMPTY, minimumVersion, unmappedResolution, timestampBounds From 6d04e7879c58aa56b2f79aaa56be214c87636505 Mon Sep 17 00:00:00 2001 From: Felix Barnsteiner Date: Mon, 23 Feb 2026 18:18:14 +0100 Subject: [PATCH 5/9] Add test to ignore `should` matchers --- ...QueryDslTimestampBoundsExtractorTests.java | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/core/querydsl/QueryDslTimestampBoundsExtractorTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/core/querydsl/QueryDslTimestampBoundsExtractorTests.java index 0f9c87c933416..70c5be0d5a8b6 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/core/querydsl/QueryDslTimestampBoundsExtractorTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/core/querydsl/QueryDslTimestampBoundsExtractorTests.java @@ -93,4 +93,49 @@ public void testExtractTimestampBoundsInvalidValueDoesNotThrow() { assertThat(bounds, nullValue()); } + public void testIgnoresRangeInShouldClause() { + var range = new RangeQueryBuilder("@timestamp").format("strict_date_optional_time") + .gte("2025-01-01T00:00:00Z") + .lte("2025-01-02T00:00:00Z"); + var filter = new BoolQueryBuilder().should(range); + + assertThat(QueryDslTimestampBoundsExtractor.extractTimestampBounds(filter), nullValue()); + } + + public void testIgnoresRangeInMustNotClause() { + var range = new RangeQueryBuilder("@timestamp").format("strict_date_optional_time") + .gte("2025-01-01T00:00:00Z") + .lte("2025-01-02T00:00:00Z"); + var filter = new BoolQueryBuilder().mustNot(range); + + assertThat(QueryDslTimestampBoundsExtractor.extractTimestampBounds(filter), nullValue()); + } + + public void testFilterRangeExtractedShouldRangeIgnored() { + Instant filterStart = Instant.parse("2025-01-01T00:00:00Z"); + Instant filterEnd = Instant.parse("2025-01-02T00:00:00Z"); + var filterRange = new RangeQueryBuilder("@timestamp").format("strict_date_optional_time") + .gte(filterStart.toString()) + .lte(filterEnd.toString()); + var shouldRange = new RangeQueryBuilder("@timestamp").format("strict_date_optional_time") + .gte("2025-06-01T00:00:00Z") + .lte("2025-06-30T00:00:00Z"); + var filter = new BoolQueryBuilder().filter(filterRange).should(shouldRange); + + TimestampBounds bounds = QueryDslTimestampBoundsExtractor.extractTimestampBounds(filter); + assertThat(bounds, notNullValue()); + assertThat(bounds.start(), equalTo(filterStart)); + assertThat(bounds.end(), equalTo(filterEnd)); + } + + public void testIgnoresRangeNestedInsideShouldSubtree() { + var range = new RangeQueryBuilder("@timestamp").format("strict_date_optional_time") + .gte("2025-01-01T00:00:00Z") + .lte("2025-01-02T00:00:00Z"); + var innerBool = new BoolQueryBuilder().should(range); + var outerBool = new BoolQueryBuilder().must(innerBool); + + assertThat(QueryDslTimestampBoundsExtractor.extractTimestampBounds(outerBool), nullValue()); + } + } From 41b6c3d1f79f39016f94a762fda0a0e8f928ae88 Mon Sep 17 00:00:00 2001 From: Felix Barnsteiner Date: Mon, 2 Mar 2026 14:58:51 +0100 Subject: [PATCH 6/9] Avoid unchecked casts by creating sub-interfaces for expressions and logical plans --- .../xpack/esql/analysis/Analyzer.java | 12 ++++------- .../xpack/esql/analysis/Verifier.java | 2 +- .../function/TimestampBoundsAware.java | 20 ++++++++++++++++++- .../plan/logical/promql/PromqlCommand.java | 4 ++-- 4 files changed, 26 insertions(+), 12 deletions(-) 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 b5d083ef85392..44e20ff0cde92 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 @@ -1737,19 +1737,15 @@ protected LogicalPlan rule(LogicalPlan plan, AnalyzerContext context) { if (bounds == null) { return plan; } - if (plan instanceof TimestampBoundsAware tba && tba.needsTimestampBounds()) { - @SuppressWarnings("unchecked") - var planAware = (TimestampBoundsAware) tba; - plan = planAware.withTimestampBounds( + if (plan instanceof TimestampBoundsAware.OfLogicalPlan tba && tba.needsTimestampBounds()) { + plan = tba.withTimestampBounds( Literal.dateTime(plan.source(), bounds.start()), Literal.dateTime(plan.source(), bounds.end()) ); } return plan.transformExpressionsUp(Expression.class, expression -> { - if (expression instanceof TimestampBoundsAware tba && tba.needsTimestampBounds()) { - @SuppressWarnings("unchecked") - var exprAware = (TimestampBoundsAware) tba; - return exprAware.withTimestampBounds( + if (expression instanceof TimestampBoundsAware.OfExpression tba && tba.needsTimestampBounds()) { + return tba.withTimestampBounds( Literal.dateTime(expression.source(), bounds.start()), Literal.dateTime(expression.source(), bounds.end()) ); 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 00dcaaebbd24e..dd680cf488117 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 @@ -224,7 +224,7 @@ else if (p instanceof PromqlCommand promql) { private static void checkUnresolvedTimestampBounds(LogicalPlan plan, Failures failures) { plan.forEachDown(p -> p.forEachExpression(Expression.class, e -> { - if (e instanceof TimestampBoundsAware tba && tba.needsTimestampBounds()) { + if (e instanceof TimestampBoundsAware.OfExpression tba && tba.needsTimestampBounds()) { failures.add( fail( e, diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/TimestampBoundsAware.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/TimestampBoundsAware.java index dcb307b9cc071..1e0a1f3b6cb2d 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/TimestampBoundsAware.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/TimestampBoundsAware.java @@ -11,7 +11,10 @@ import org.elasticsearch.xpack.esql.analysis.Verifier; import org.elasticsearch.xpack.esql.capabilities.ConfigurationAware; import org.elasticsearch.xpack.esql.capabilities.PostAnalysisVerificationAware; +import org.elasticsearch.xpack.esql.core.expression.Expression; import org.elasticsearch.xpack.esql.core.expression.Literal; +import org.elasticsearch.xpack.esql.core.tree.Node; +import org.elasticsearch.xpack.esql.plan.logical.LogicalPlan; /** * Marker interface for nodes (expressions or plans) that require {@code @timestamp} bounds derived from the query DSL filter. @@ -24,10 +27,15 @@ * rejected by the {@link Verifier} with a client error. * LogicalPlan implementations are responsible for their own validation via {@link PostAnalysisVerificationAware#postAnalysisVerification}. *

+ *

+ * Use the sub-interfaces {@link OfExpression} and {@link OfLogicalPlan} + * rather than implementing this interface directly. + *

* * @param the type returned by {@link #withTimestampBounds}, typically {@code Expression} or {@code LogicalPlan} */ -public interface TimestampBoundsAware { +public sealed interface TimestampBoundsAware> permits TimestampBoundsAware.OfExpression, + TimestampBoundsAware.OfLogicalPlan { /** * Returns {@code true} if this node still needs timestamp bounds to be injected. @@ -38,4 +46,14 @@ public interface TimestampBoundsAware { * Returns a copy of this node with the given timestamp bounds applied. */ T withTimestampBounds(Literal start, Literal end); + + /** + * Sub-interface for {@link Expression} nodes that require timestamp bounds. + */ + non-sealed interface OfExpression extends TimestampBoundsAware {} + + /** + * Sub-interface for {@link LogicalPlan} nodes that require timestamp bounds. + */ + non-sealed interface OfLogicalPlan extends TimestampBoundsAware {} } diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/promql/PromqlCommand.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/promql/PromqlCommand.java index 1a987143c8f05..32a3d9e5098c9 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/promql/PromqlCommand.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/promql/PromqlCommand.java @@ -50,7 +50,7 @@ public class PromqlCommand extends UnaryPlan TelemetryAware, PostAnalysisVerificationAware, TimestampAware, - TimestampBoundsAware { + TimestampBoundsAware.OfLogicalPlan { /** * The name of the column containing the step value (aka time bucket) in range queries. @@ -179,7 +179,7 @@ public boolean needsTimestampBounds() { } @Override - public LogicalPlan withTimestampBounds(Literal start, Literal end) { + public PromqlCommand withTimestampBounds(Literal start, Literal end) { return new PromqlCommand( source(), child(), From 20778377f9230ecddf14eb9e4673fa6422ff35b0 Mon Sep 17 00:00:00 2001 From: Felix Barnsteiner Date: Fri, 6 Mar 2026 09:31:48 +0100 Subject: [PATCH 7/9] Make implementations of TimestampBoundsAware responsible for the validation --- .../xpack/esql/analysis/Verifier.java | 15 --------------- .../expression/function/TimestampBoundsAware.java | 11 ++++------- 2 files changed, 4 insertions(+), 22 deletions(-) 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 dd680cf488117..c0b77d1674ea3 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 @@ -96,7 +96,6 @@ Collection verify(LogicalPlan plan, BitSet partialMetrics) { checkUnresolvedAttributes(plan, failures); ConfigurationAware.verifyNoMarkerConfiguration(plan, failures); - checkUnresolvedTimestampBounds(plan, failures); // in case of failures bail-out as all other checks will be redundant if (failures.hasFailures()) { @@ -222,20 +221,6 @@ else if (p instanceof PromqlCommand promql) { }); } - private static void checkUnresolvedTimestampBounds(LogicalPlan plan, Failures failures) { - plan.forEachDown(p -> p.forEachExpression(Expression.class, e -> { - if (e instanceof TimestampBoundsAware.OfExpression tba && tba.needsTimestampBounds()) { - failures.add( - fail( - e, - "[{}] requires a time range; provide explicit from/to parameters or add a @timestamp range to the query filter", - e.sourceText() - ) - ); - } - })); - } - /** * Build a list of checkers based on the components in the plan. */ diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/TimestampBoundsAware.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/TimestampBoundsAware.java index 1e0a1f3b6cb2d..86fcc46aaac39 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/TimestampBoundsAware.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/TimestampBoundsAware.java @@ -8,7 +8,6 @@ package org.elasticsearch.xpack.esql.expression.function; import org.elasticsearch.xpack.esql.analysis.Analyzer; -import org.elasticsearch.xpack.esql.analysis.Verifier; import org.elasticsearch.xpack.esql.capabilities.ConfigurationAware; import org.elasticsearch.xpack.esql.capabilities.PostAnalysisVerificationAware; import org.elasticsearch.xpack.esql.core.expression.Expression; @@ -19,13 +18,11 @@ /** * Marker interface for nodes (expressions or plans) that require {@code @timestamp} bounds derived from the query DSL filter. *

- * Implementations are resolved during analysis by {@link Analyzer}'s {@code ResolveTimestampBoundsAware} rule, + * Implementations are resolved during analysis by the {@code ResolveTimestampBoundsAware} analyzer rule, * following the same pattern as {@link ConfigurationAware}. *

*

- * Expression implementations that still {@link #needsTimestampBounds() need bounds} after analysis are automatically - * rejected by the {@link Verifier} with a client error. - * LogicalPlan implementations are responsible for their own validation via {@link PostAnalysisVerificationAware#postAnalysisVerification}. + * Implementations are responsible for their own validation via {@link PostAnalysisVerificationAware#postAnalysisVerification}. *

*

* Use the sub-interfaces {@link OfExpression} and {@link OfLogicalPlan} @@ -34,8 +31,8 @@ * * @param the type returned by {@link #withTimestampBounds}, typically {@code Expression} or {@code LogicalPlan} */ -public sealed interface TimestampBoundsAware> permits TimestampBoundsAware.OfExpression, - TimestampBoundsAware.OfLogicalPlan { +public sealed interface TimestampBoundsAware> extends PostAnalysisVerificationAware permits + TimestampBoundsAware.OfExpression, TimestampBoundsAware.OfLogicalPlan { /** * Returns {@code true} if this node still needs timestamp bounds to be injected. From ebb5b1f36fc75f7b0540a4a18b49627b9eb3736a Mon Sep 17 00:00:00 2001 From: elasticsearchmachine Date: Fri, 6 Mar 2026 08:37:41 +0000 Subject: [PATCH 8/9] [CI] Auto commit changes from spotless --- .../java/org/elasticsearch/xpack/esql/analysis/Verifier.java | 1 - .../xpack/esql/expression/function/TimestampBoundsAware.java | 1 - 2 files changed, 2 deletions(-) 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 c0b77d1674ea3..c21d72b71e8bd 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 @@ -24,7 +24,6 @@ import org.elasticsearch.xpack.esql.core.tree.Node; import org.elasticsearch.xpack.esql.core.type.DataType; import org.elasticsearch.xpack.esql.core.util.Holder; -import org.elasticsearch.xpack.esql.expression.function.TimestampBoundsAware; import org.elasticsearch.xpack.esql.expression.function.UnsupportedAttribute; import org.elasticsearch.xpack.esql.expression.predicate.operator.arithmetic.Neg; import org.elasticsearch.xpack.esql.expression.predicate.operator.comparison.Equals; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/TimestampBoundsAware.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/TimestampBoundsAware.java index 86fcc46aaac39..ec375cdc46823 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/TimestampBoundsAware.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/TimestampBoundsAware.java @@ -7,7 +7,6 @@ package org.elasticsearch.xpack.esql.expression.function; -import org.elasticsearch.xpack.esql.analysis.Analyzer; import org.elasticsearch.xpack.esql.capabilities.ConfigurationAware; import org.elasticsearch.xpack.esql.capabilities.PostAnalysisVerificationAware; import org.elasticsearch.xpack.esql.core.expression.Expression; From f2c542472eb0615203398c3226572cf8570b12ec Mon Sep 17 00:00:00 2001 From: elasticsearchmachine Date: Wed, 11 Mar 2026 14:58:06 +0000 Subject: [PATCH 9/9] [CI] Auto commit changes from spotless --- .../java/org/elasticsearch/xpack/esql/session/EsqlSession.java | 1 - 1 file changed, 1 deletion(-) diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java index 47397e766a5c5..0674314c637ca 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java @@ -56,7 +56,6 @@ import org.elasticsearch.xpack.esql.core.expression.Attribute; import org.elasticsearch.xpack.esql.core.expression.Expression; import org.elasticsearch.xpack.esql.core.expression.FoldContext; -import org.elasticsearch.xpack.esql.core.expression.Literal; import org.elasticsearch.xpack.esql.core.querydsl.QueryDslTimestampBoundsExtractor; import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.datasources.ExternalSourceResolution;