Skip to content

Commit f6b8a44

Browse files
authored
ES|QL: Restrict sorting for _source and counter field types (#114638) (#114706)
(cherry picked from commit 2af19d8)
1 parent 3e51698 commit f6b8a44

File tree

10 files changed

+80
-9
lines changed

10 files changed

+80
-9
lines changed

docs/changelog/114638.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
pr: 114638
2+
summary: "ES|QL: Restrict sorting for `_source` and counter field types"
3+
area: ES|QL
4+
type: bug
5+
issues:
6+
- 114423
7+
- 111976

x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/type/DataType.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,10 @@ public static boolean isRepresentable(DataType t) {
425425
&& t.isCounter() == false;
426426
}
427427

428+
public static boolean isCounter(DataType t) {
429+
return t == COUNTER_DOUBLE || t == COUNTER_INTEGER || t == COUNTER_LONG;
430+
}
431+
428432
public static boolean isSpatialPoint(DataType t) {
429433
return t == GEO_POINT || t == CARTESIAN_POINT;
430434
}
@@ -437,6 +441,10 @@ public static boolean isSpatial(DataType t) {
437441
return t == GEO_POINT || t == CARTESIAN_POINT || t == GEO_SHAPE || t == CARTESIAN_SHAPE;
438442
}
439443

444+
public static boolean isSortable(DataType t) {
445+
return false == (t == SOURCE || isCounter(t) || isSpatial(t));
446+
}
447+
440448
public String nameUpper() {
441449
return name;
442450
}

x-pack/plugin/esql/qa/testFixtures/src/main/resources/tsdb-mapping.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@
2727
"message_in": {
2828
"type": "float",
2929
"time_series_metric": "counter"
30+
},
31+
"message_out": {
32+
"type": "integer",
33+
"time_series_metric": "counter"
3034
}
3135
}
3236
}

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -360,7 +360,12 @@ public enum Cap {
360360
/**
361361
* Support named parameters for field names.
362362
*/
363-
NAMED_PARAMETER_FOR_FIELD_AND_FUNCTION_NAMES;
363+
NAMED_PARAMETER_FOR_FIELD_AND_FUNCTION_NAMES,
364+
365+
/**
366+
* Fix sorting not allowed on _source and counters.
367+
*/
368+
SORTING_ON_SOURCE_AND_COUNTERS_FORBIDDEN;
364369

365370
private final boolean snapshotOnly;
366371
private final FeatureFlag featureFlag;

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/analysis/Verifier.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ else if (p instanceof Lookup lookup) {
183183

184184
checkOperationsOnUnsignedLong(p, failures);
185185
checkBinaryComparison(p, failures);
186-
checkForSortOnSpatialTypes(p, failures);
186+
checkForSortableDataTypes(p, failures);
187187

188188
checkFilterMatchConditions(p, failures);
189189
checkFullTextQueryFunctions(p, failures);
@@ -548,12 +548,12 @@ private static Failure validateUnsignedLongNegation(Neg neg) {
548548
}
549549

550550
/**
551-
* Makes sure that spatial types do not appear in sorting contexts.
551+
* Some datatypes are not sortable
552552
*/
553-
private static void checkForSortOnSpatialTypes(LogicalPlan p, Set<Failure> localFailures) {
553+
private static void checkForSortableDataTypes(LogicalPlan p, Set<Failure> localFailures) {
554554
if (p instanceof OrderBy ob) {
555555
ob.order().forEach(order -> {
556-
if (DataType.isSpatial(order.dataType())) {
556+
if (DataType.isSortable(order.dataType()) == false) {
557557
localFailures.add(fail(order, "cannot sort on " + order.dataType().typeName()));
558558
}
559559
});

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Rate.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ public DataType dataType() {
115115
protected TypeResolution resolveType() {
116116
TypeResolution resolution = isType(
117117
field(),
118-
dt -> dt == DataType.COUNTER_LONG || dt == DataType.COUNTER_INTEGER || dt == DataType.COUNTER_DOUBLE,
118+
dt -> DataType.isCounter(dt),
119119
sourceText(),
120120
FIRST,
121121
"counter_long",

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1645,7 +1645,7 @@ public void testCounterTypes() {
16451645
var attributes = limit.output().stream().collect(Collectors.toMap(NamedExpression::name, a -> a));
16461646
assertThat(
16471647
attributes.keySet(),
1648-
equalTo(Set.of("network.connections", "network.bytes_in", "network.bytes_out", "network.message_in"))
1648+
equalTo(Set.of("network.connections", "network.bytes_in", "network.bytes_out", "network.message_in", "network.message_out"))
16491649
);
16501650
assertThat(attributes.get("network.connections").dataType(), equalTo(DataType.LONG));
16511651
assertThat(attributes.get("network.bytes_in").dataType(), equalTo(DataType.COUNTER_LONG));

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

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,16 @@
2525
import java.util.LinkedHashMap;
2626
import java.util.LinkedHashSet;
2727
import java.util.List;
28+
import java.util.Locale;
2829
import java.util.Map;
2930
import java.util.Set;
3031

3132
import static org.elasticsearch.xpack.esql.EsqlTestUtils.paramAsConstant;
3233
import static org.elasticsearch.xpack.esql.EsqlTestUtils.withDefaultLimitWarning;
3334
import static org.elasticsearch.xpack.esql.analysis.AnalyzerTestUtils.loadMapping;
35+
import static org.elasticsearch.xpack.esql.core.type.DataType.COUNTER_DOUBLE;
36+
import static org.elasticsearch.xpack.esql.core.type.DataType.COUNTER_INTEGER;
37+
import static org.elasticsearch.xpack.esql.core.type.DataType.COUNTER_LONG;
3438
import static org.elasticsearch.xpack.esql.core.type.DataType.UNSIGNED_LONG;
3539
import static org.hamcrest.Matchers.containsString;
3640
import static org.hamcrest.Matchers.equalTo;
@@ -908,6 +912,25 @@ public void testSpatialSort() {
908912
assertEquals("1:42: cannot sort on cartesian_shape", error("FROM countries_bbox_web | LIMIT 5 | sort shape", countriesBboxWeb));
909913
}
910914

915+
public void testSourceSorting() {
916+
assertEquals("1:35: cannot sort on _source", error("from test metadata _source | sort _source"));
917+
}
918+
919+
public void testCountersSorting() {
920+
Map<DataType, String> counterDataTypes = Map.of(
921+
COUNTER_DOUBLE,
922+
"network.message_in",
923+
COUNTER_INTEGER,
924+
"network.message_out",
925+
COUNTER_LONG,
926+
"network.bytes_out"
927+
);
928+
for (DataType counterDT : counterDataTypes.keySet()) {
929+
var fieldName = counterDataTypes.get(counterDT);
930+
assertEquals("1:18: cannot sort on " + counterDT.name().toLowerCase(Locale.ROOT), error("from test | sort " + fieldName, tsdb));
931+
}
932+
}
933+
911934
public void testInlineImpossibleConvert() {
912935
assertEquals("1:5: argument of [false::ip] must be [ip or string], found value [false] type [boolean]", error("ROW false::ip"));
913936
}

x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/esql/140_metadata.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,3 +155,19 @@ setup:
155155
esql.query:
156156
body:
157157
query: 'FROM test [metadata _source] | STATS COUNT_DISTINCT(_source)'
158+
159+
---
160+
"sort on _source not allowed":
161+
- requires:
162+
test_runner_features: [capabilities]
163+
capabilities:
164+
- method: POST
165+
path: /_query
166+
parameters: []
167+
capabilities: [sorting_on_source_and_counters_forbidden]
168+
reason: "Sorting on _source shouldn't have been possible"
169+
- do:
170+
catch: /cannot sort on _source/
171+
esql.query:
172+
body:
173+
query: 'FROM test metadata _source | sort _source'

x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/esql/40_tsdb.yml

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -178,11 +178,19 @@ cast counter then filter:
178178

179179
---
180180
sort on counter without cast:
181+
- requires:
182+
test_runner_features: [capabilities]
183+
capabilities:
184+
- method: POST
185+
path: /_query
186+
parameters: []
187+
capabilities: [sorting_on_source_and_counters_forbidden]
188+
reason: "Sorting on counters shouldn't have been possible"
181189
- do:
182-
catch: bad_request
190+
catch: /cannot sort on counter_long/
183191
esql.query:
184192
body:
185-
query: 'from test | KEEP k8s.pod.network.tx | sort @k8s.pod.network.tx | limit 1'
193+
query: 'from test | KEEP k8s.pod.network.tx | sort k8s.pod.network.tx | limit 1'
186194

187195
---
188196
cast then sort on counter:

0 commit comments

Comments
 (0)