Skip to content

Commit 9d4432c

Browse files
committed
Mirror upstream elastic#137264 as single snapshot commit for AI review
BASE=d44915bad6c9de2442659d6bd00304107d24a8f2 HEAD=d34c710cf9a9d44f330d7455b36ef4ae7390bcbb Branch=esql/promql
1 parent d44915b commit 9d4432c

File tree

6 files changed

+176
-12
lines changed

6 files changed

+176
-12
lines changed

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/LogicalPlanOptimizer.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -117,10 +117,10 @@ public LogicalPlanOptimizer(LogicalOptimizerContext optimizerContext) {
117117
public LogicalPlan optimize(LogicalPlan verified) {
118118
var optimized = execute(verified);
119119

120-
// Failures failures = verifier.verify(optimized, verified.output());
121-
// if (failures.hasFailures()) {
122-
// throw new VerificationException(failures);
123-
// }
120+
// Failures failures = verifier.verify(optimized, verified.output());
121+
// if (failures.hasFailures()) {
122+
// throw new VerificationException(failures);
123+
// }
124124
optimized.setOptimized();
125125
return optimized;
126126
}

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/promql/PromqlCommand.java

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,23 +8,29 @@
88
package org.elasticsearch.xpack.esql.plan.logical.promql;
99

1010
import org.elasticsearch.common.io.stream.StreamOutput;
11+
import org.elasticsearch.core.TimeValue;
12+
import org.elasticsearch.xpack.esql.capabilities.PostAnalysisVerificationAware;
1113
import org.elasticsearch.xpack.esql.capabilities.TelemetryAware;
14+
import org.elasticsearch.xpack.esql.common.Failures;
1215
import org.elasticsearch.xpack.esql.core.expression.Expression;
1316
import org.elasticsearch.xpack.esql.core.expression.Literal;
1417
import org.elasticsearch.xpack.esql.core.tree.NodeInfo;
1518
import org.elasticsearch.xpack.esql.core.tree.Source;
1619
import org.elasticsearch.xpack.esql.plan.logical.LogicalPlan;
1720
import org.elasticsearch.xpack.esql.plan.logical.UnaryPlan;
21+
import org.elasticsearch.xpack.esql.plan.logical.promql.selector.Selector;
1822

1923
import java.io.IOException;
2024
import java.time.Duration;
2125
import java.util.Objects;
2226

27+
import static org.elasticsearch.xpack.esql.common.Failure.fail;
28+
2329
/**
2430
* Container plan for embedded PromQL queries.
2531
* Gets eliminated by the analyzer once the query is validated.
2632
*/
27-
public class PromqlCommand extends UnaryPlan implements TelemetryAware {
33+
public class PromqlCommand extends UnaryPlan implements TelemetryAware, PostAnalysisVerificationAware {
2834

2935
private final LogicalPlan promqlPlan;
3036
private final Expression start, end, step;
@@ -102,9 +108,9 @@ public int hashCode() {
102108
public boolean equals(Object obj) {
103109
if (super.equals(obj)) {
104110

105-
PromqlCommand other = (PromqlCommand) obj;
106-
return Objects.equals(child(), other.child()) && Objects.equals(promqlPlan, other.promqlPlan);
107-
}
111+
PromqlCommand other = (PromqlCommand) obj;
112+
return Objects.equals(child(), other.child()) && Objects.equals(promqlPlan, other.promqlPlan);
113+
}
108114

109115
return false;
110116
}
@@ -123,4 +129,38 @@ public String nodeString() {
123129
sb.append("\n<>]]");
124130
return sb.toString();
125131
}
132+
133+
@Override
134+
public void postAnalysisVerification(Failures failures) {
135+
promqlPlan().forEachDownMayReturnEarly((lp, breakEarly) -> {
136+
if (lp instanceof PromqlFunctionCall fc) {
137+
if (fc instanceof AcrossSeriesAggregate) {
138+
breakEarly.set(true);
139+
fc.forEachDown((childLp -> verifyNonFunctionCall(failures, childLp)));
140+
} else if (fc instanceof WithinSeriesAggregate withinSeriesAggregate) {
141+
failures.add(
142+
fail(
143+
withinSeriesAggregate,
144+
"within time series aggregate function [{}] "
145+
+ "can only be used inside an across time series aggregate function at this time",
146+
withinSeriesAggregate.sourceText()
147+
)
148+
);
149+
}
150+
} else {
151+
verifyNonFunctionCall(failures, lp);
152+
}
153+
});
154+
}
155+
156+
private void verifyNonFunctionCall(Failures failures, LogicalPlan logicalPlan) {
157+
if (logicalPlan instanceof Selector s) {
158+
if (s.labelMatchers().nameLabel().matcher().isRegex()) {
159+
failures.add(fail(s, "regex label selectors on __name__ are not supported at this time [{}]", s.sourceText()));
160+
}
161+
if (s.evaluation().offset() != null && s.evaluation().offset() != TimeValue.ZERO) {
162+
failures.add(fail(s, "offset modifiers are not supported at this time [{}]", s.sourceText()));
163+
}
164+
}
165+
}
126166
}

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/promql/selector/LabelMatcher.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,10 @@ public static Matcher from(String value) {
6060
this.value = value;
6161
this.isRegex = isRegex;
6262
}
63+
64+
public boolean isRegex() {
65+
return isRegex;
66+
}
6367
}
6468

6569
private final String name;

x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/VerifierTests.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3086,15 +3086,15 @@ private String error(String query, Object... params) {
30863086
return error(query, defaultAnalyzer, VerificationException.class, params);
30873087
}
30883088

3089-
private String error(String query, Analyzer analyzer, Object... params) {
3089+
public static String error(String query, Analyzer analyzer, Object... params) {
30903090
return error(query, analyzer, VerificationException.class, params);
30913091
}
30923092

30933093
private String error(String query, TransportVersion transportVersion, Object... params) {
30943094
return error(query, transportVersion, VerificationException.class, params);
30953095
}
30963096

3097-
private String error(String query, Analyzer analyzer, Class<? extends Exception> exception, Object... params) {
3097+
public static String error(String query, Analyzer analyzer, Class<? extends Exception> exception, Object... params) {
30983098
List<QueryParam> parameters = new ArrayList<>();
30993099
for (Object param : params) {
31003100
if (param == null) {
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License
4+
* 2.0; you may not use this file except in compliance with the Elastic License
5+
* 2.0.
6+
*/
7+
8+
package org.elasticsearch.xpack.esql.analysis.promql;
9+
10+
import org.elasticsearch.test.ESTestCase;
11+
import org.elasticsearch.xpack.esql.analysis.Analyzer;
12+
import org.elasticsearch.xpack.esql.analysis.AnalyzerTestUtils;
13+
import org.junit.Ignore;
14+
15+
import java.util.List;
16+
17+
import static org.elasticsearch.xpack.esql.EsqlTestUtils.withDefaultLimitWarning;
18+
import static org.elasticsearch.xpack.esql.analysis.VerifierTests.error;
19+
import static org.hamcrest.Matchers.equalTo;
20+
21+
public class PromqlVerifierTests extends ESTestCase {
22+
23+
private final Analyzer tsdb = AnalyzerTestUtils.analyzer(AnalyzerTestUtils.tsdbIndexResolution());
24+
25+
public void testPromqlMissingAcrossSeriesAggregation() {
26+
assertThat(
27+
error("""
28+
TS test | PROMQL step 5m (
29+
rate(network.bytes_in[5m])
30+
)""", tsdb),
31+
equalTo(
32+
"2:3: within time series aggregate function [rate(network.bytes_in[5m])] can only be used "
33+
+ "inside an across time series aggregate function at this time"
34+
)
35+
);
36+
}
37+
38+
public void testPromqlIllegalNameLabelMatcher() {
39+
assertThat(
40+
error("TS test | PROMQL step 5m ({__name__=~\"*.foo.*\"})", tsdb),
41+
equalTo("1:27: regex label selectors on __name__ are not supported at this time [{__name__=~\"*.foo.*\"}]")
42+
);
43+
}
44+
45+
@Ignore
46+
public void testPromqlSubquery() {
47+
// TODO doesn't parse
48+
// line 1:36: Invalid query 'network.bytes_in'[ValueExpressionContext] given; expected Expression but found
49+
// InstantSelector
50+
assertThat(error("TS test | PROMQL step 5m (avg(rate(network.bytes_in[5m:])))", tsdb), equalTo(""));
51+
assertThat(error("TS test | PROMQL step 5m (avg(rate(network.bytes_in[5m:1m])))", tsdb), equalTo(""));
52+
}
53+
54+
@Ignore
55+
public void testPromqlArithmetricOperators() {
56+
// TODO doesn't parse
57+
// line 1:27: Invalid query '1+1'[ArithmeticBinaryContext] given; expected LogicalPlan but found VectorBinaryArithmetic
58+
assertThat(
59+
error("TS test | PROMQL step 5m (1+1)", tsdb),
60+
equalTo("1:27: arithmetic operators are not supported at this time [foo]")
61+
);
62+
assertThat(
63+
error("TS test | PROMQL step 5m (foo+1)", tsdb),
64+
equalTo("1:27: arithmetic operators are not supported at this time [foo]")
65+
);
66+
assertThat(
67+
error("TS test | PROMQL step 5m (1+foo)", tsdb),
68+
equalTo("1:27: arithmetic operators are not supported at this time [foo]")
69+
);
70+
assertThat(
71+
error("TS test | PROMQL step 5m (foo+bar)", tsdb),
72+
equalTo("1:27: arithmetic operators are not supported at this time [foo]")
73+
);
74+
}
75+
76+
@Ignore
77+
public void testPromqlVectorMatching() {
78+
// TODO doesn't parse
79+
// line 1:27: Invalid query 'method_code_http_errors_rate5m{code="500"}'[ValueExpressionContext] given; expected Expression but
80+
// found InstantSelector
81+
assertThat(
82+
error(
83+
"TS test | PROMQL step 5m (method_code_http_errors_rate5m{code=\"500\"} / ignoring(code) method_http_requests_rate5m)",
84+
tsdb
85+
),
86+
equalTo("")
87+
);
88+
assertThat(
89+
error(
90+
"TS test | PROMQL step 5m (method_code_http_errors_rate5m / ignoring(code) group_left method_http_requests_rate5m)",
91+
tsdb
92+
),
93+
equalTo("")
94+
);
95+
}
96+
97+
public void testPromqlModifier() {
98+
assertThat(
99+
error("TS test | PROMQL step 5m (foo offset 5m)", tsdb),
100+
equalTo("1:27: offset modifiers are not supported at this time [foo offset 5m]")
101+
);
102+
/* TODO
103+
assertThat(
104+
error("TS test | PROMQL step 5m (foo @ start())", tsdb),
105+
equalTo("1:27: @ modifiers are not supported at this time [foo @ start()]")
106+
);*/
107+
}
108+
109+
@Ignore
110+
public void testLogicalSetBinaryOperators() {
111+
// TODO doesn't parse
112+
// line 1:27: Invalid query 'foo'[ValueExpressionContext] given; expected Expression but found InstantSelector
113+
assertThat(error("TS test | PROMQL step 5m (foo and bar)", tsdb), equalTo(""));
114+
assertThat(error("TS test | PROMQL step 5m (foo or bar)", tsdb), equalTo(""));
115+
assertThat(error("TS test | PROMQL step 5m (foo unless bar)", tsdb), equalTo(""));
116+
}
117+
118+
@Override
119+
protected List<String> filteredWarnings() {
120+
return withDefaultLimitWarning(super.filteredWarnings());
121+
}
122+
}

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

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99

1010
import org.elasticsearch.TransportVersion;
1111
import org.elasticsearch.index.IndexMode;
12-
import org.elasticsearch.transport.Transport;
1312
import org.elasticsearch.xpack.esql.EsqlTestUtils;
1413
import org.elasticsearch.xpack.esql.action.EsqlCapabilities;
1514
import org.elasticsearch.xpack.esql.analysis.Analyzer;
@@ -23,7 +22,6 @@
2322
import org.elasticsearch.xpack.esql.plan.logical.LogicalPlan;
2423
import org.junit.BeforeClass;
2524

26-
import java.util.Collections;
2725
import java.util.Map;
2826

2927
import static java.util.Collections.emptyMap;

0 commit comments

Comments
 (0)