Skip to content

Commit 4d7fd21

Browse files
Merge branch 'main' into fixElasticsearchServiceBug
2 parents 5180702 + 14f0b48 commit 4d7fd21

File tree

31 files changed

+3173
-1825
lines changed

31 files changed

+3173
-1825
lines changed

build-tools-internal/src/integTest/groovy/org/elasticsearch/gradle/internal/PublishPluginFuncTest.groovy

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -70,13 +70,13 @@ class PublishPluginFuncTest extends AbstractGradleFuncTest {
7070
<distribution>repo</distribution>
7171
</license>
7272
<license>
73-
<name>Server Side Public License, v 1</name>
74-
<url>https://www.mongodb.com/licensing/server-side-public-license</url>
73+
<name>GNU Affero General Public License Version 3</name>
74+
<url>https://raw.githubusercontent.com/elastic/elasticsearch/v1.0/licenses/AGPL-3.0+SSPL-1.0+ELASTIC-LICENSE-2.0.txt</url>
7575
<distribution>repo</distribution>
7676
</license>
7777
<license>
78-
<name>The OSI-approved Open Source license Version 3.0</name>
79-
<url>https://raw.githubusercontent.com/elastic/elasticsearch/v1.0/licenses/AGPL-3.0+SSPL-1.0+ELASTIC-LICENSE-2.0.txt</url>
78+
<name>Server Side Public License, v 1</name>
79+
<url>https://www.mongodb.com/licensing/server-side-public-license</url>
8080
<distribution>repo</distribution>
8181
</license>
8282
</licenses>
@@ -150,13 +150,13 @@ class PublishPluginFuncTest extends AbstractGradleFuncTest {
150150
<distribution>repo</distribution>
151151
</license>
152152
<license>
153-
<name>Server Side Public License, v 1</name>
154-
<url>https://www.mongodb.com/licensing/server-side-public-license</url>
153+
<name>GNU Affero General Public License Version 3</name>
154+
<url>https://raw.githubusercontent.com/elastic/elasticsearch/v1.0/licenses/AGPL-3.0+SSPL-1.0+ELASTIC-LICENSE-2.0.txt</url>
155155
<distribution>repo</distribution>
156156
</license>
157157
<license>
158-
<name>The OSI-approved Open Source license Version 3.0</name>
159-
<url>https://raw.githubusercontent.com/elastic/elasticsearch/v1.0/licenses/AGPL-3.0+SSPL-1.0+ELASTIC-LICENSE-2.0.txt</url>
158+
<name>Server Side Public License, v 1</name>
159+
<url>https://www.mongodb.com/licensing/server-side-public-license</url>
160160
<distribution>repo</distribution>
161161
</license>
162162
</licenses>
@@ -239,13 +239,13 @@ class PublishPluginFuncTest extends AbstractGradleFuncTest {
239239
<distribution>repo</distribution>
240240
</license>
241241
<license>
242-
<name>Server Side Public License, v 1</name>
243-
<url>https://www.mongodb.com/licensing/server-side-public-license</url>
242+
<name>GNU Affero General Public License Version 3</name>
243+
<url>https://raw.githubusercontent.com/elastic/elasticsearch/v1.0/licenses/AGPL-3.0+SSPL-1.0+ELASTIC-LICENSE-2.0.txt</url>
244244
<distribution>repo</distribution>
245245
</license>
246246
<license>
247-
<name>The OSI-approved Open Source license Version 3.0</name>
248-
<url>https://raw.githubusercontent.com/elastic/elasticsearch/v1.0/licenses/AGPL-3.0+SSPL-1.0+ELASTIC-LICENSE-2.0.txt</url>
247+
<name>Server Side Public License, v 1</name>
248+
<url>https://www.mongodb.com/licensing/server-side-public-license</url>
249249
<distribution>repo</distribution>
250250
</license>
251251
</licenses>
@@ -337,13 +337,13 @@ class PublishPluginFuncTest extends AbstractGradleFuncTest {
337337
<distribution>repo</distribution>
338338
</license>
339339
<license>
340-
<name>Server Side Public License, v 1</name>
341-
<url>https://www.mongodb.com/licensing/server-side-public-license</url>
340+
<name>GNU Affero General Public License Version 3</name>
341+
<url>https://raw.githubusercontent.com/elastic/elasticsearch/v1.0/licenses/AGPL-3.0+SSPL-1.0+ELASTIC-LICENSE-2.0.txt</url>
342342
<distribution>repo</distribution>
343343
</license>
344344
<license>
345-
<name>The OSI-approved Open Source license Version 3.0</name>
346-
<url>https://raw.githubusercontent.com/elastic/elasticsearch/v1.0/licenses/AGPL-3.0+SSPL-1.0+ELASTIC-LICENSE-2.0.txt</url>
345+
<name>Server Side Public License, v 1</name>
346+
<url>https://www.mongodb.com/licensing/server-side-public-license</url>
347347
<distribution>repo</distribution>
348348
</license>
349349
</licenses>
@@ -415,13 +415,13 @@ class PublishPluginFuncTest extends AbstractGradleFuncTest {
415415
<distribution>repo</distribution>
416416
</license>
417417
<license>
418-
<name>Server Side Public License, v 1</name>
419-
<url>https://www.mongodb.com/licensing/server-side-public-license</url>
418+
<name>GNU Affero General Public License Version 3</name>
419+
<url>https://raw.githubusercontent.com/elastic/elasticsearch/v2.0/licenses/AGPL-3.0+SSPL-1.0+ELASTIC-LICENSE-2.0.txt</url>
420420
<distribution>repo</distribution>
421421
</license>
422422
<license>
423-
<name>The OSI-approved Open Source license Version 3.0</name>
424-
<url>https://raw.githubusercontent.com/elastic/elasticsearch/v2.0/licenses/AGPL-3.0+SSPL-1.0+ELASTIC-LICENSE-2.0.txt</url>
423+
<name>Server Side Public License, v 1</name>
424+
<url>https://www.mongodb.com/licensing/server-side-public-license</url>
425425
<distribution>repo</distribution>
426426
</license>
427427
</licenses>

docs/changelog/112905.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
pr: 112905
2+
summary: "[ES|QL] Named parameter for field names and field name patterns"
3+
area: ES|QL
4+
type: enhancement
5+
issues: []

server/src/main/java/org/elasticsearch/common/util/LongObjectPagedHashMap.java

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ public T get(long key) {
6363
* an insertion.
6464
*/
6565
public T put(long key, T value) {
66+
assert value != null : "Null values are not supported";
6667
if (size >= maxSize) {
6768
assert size == maxSize;
6869
grow();
@@ -94,9 +95,6 @@ public T remove(long key) {
9495
}
9596

9697
private T set(long key, T value) {
97-
if (value == null) {
98-
throw new IllegalArgumentException("Null values are not supported");
99-
}
10098
for (long i = slot(hash(key), mask);; i = nextSlot(i, mask)) {
10199
final T previous = values.getAndSet(i, value);
102100
if (previous == null) {
@@ -116,7 +114,7 @@ private T set(long key, T value) {
116114

117115
@Override
118116
public Iterator<Cursor<T>> iterator() {
119-
return new Iterator<Cursor<T>>() {
117+
return new Iterator<>() {
120118

121119
boolean cached;
122120
final Cursor<T> cursor;
@@ -181,9 +179,21 @@ protected boolean used(long bucket) {
181179
protected void removeAndAdd(long index) {
182180
final long key = keys.get(index);
183181
final T value = values.getAndSet(index, null);
184-
--size;
185-
final T removed = set(key, value);
186-
assert removed == null;
182+
reset(key, value);
183+
}
184+
185+
private void reset(long key, T value) {
186+
final ObjectArray<T> values = this.values;
187+
final long mask = this.mask;
188+
for (long i = slot(hash(key), mask);; i = nextSlot(i, mask)) {
189+
final T previous = values.get(i);
190+
if (previous == null) {
191+
// slot was free
192+
keys.set(i, key);
193+
values.set(i, value);
194+
break;
195+
}
196+
}
187197
}
188198

189199
public static final class Cursor<T> {

server/src/main/java/org/elasticsearch/common/util/ObjectObjectPagedHashMap.java

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ public V get(K key) {
6767
* an insertion.
6868
*/
6969
public V put(K key, V value) {
70+
assert value != null : "Null values are not supported";
7071
if (size >= maxSize) {
7172
assert size == maxSize;
7273
grow();
@@ -100,7 +101,6 @@ public V remove(K key) {
100101

101102
private V set(K key, int code, V value) {
102103
assert key.hashCode() == code;
103-
assert value != null;
104104
assert size < maxSize;
105105
final long slot = slot(code, mask);
106106
for (long index = slot;; index = nextSlot(index, mask)) {
@@ -187,9 +187,22 @@ protected boolean used(long bucket) {
187187
protected void removeAndAdd(long index) {
188188
final K key = keys.get(index);
189189
final V value = values.getAndSet(index, null);
190-
--size;
191-
final V removed = set(key, key.hashCode(), value);
192-
assert removed == null;
190+
reset(key, value);
191+
}
192+
193+
private void reset(K key, V value) {
194+
final ObjectArray<V> values = this.values;
195+
final long mask = this.mask;
196+
final long slot = slot(key.hashCode(), mask);
197+
for (long index = slot;; index = nextSlot(index, mask)) {
198+
final V previous = values.get(index);
199+
if (previous == null) {
200+
// slot was free
201+
values.set(index, value);
202+
keys.set(index, key);
203+
break;
204+
}
205+
}
193206
}
194207

195208
public static final class Cursor<K, V> {

x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/RestEsqlTestCase.java

Lines changed: 129 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
import java.util.regex.Pattern;
5656

5757
import static java.util.Collections.emptySet;
58+
import static java.util.Map.entry;
5859
import static org.elasticsearch.common.logging.LoggerMessageFormat.format;
5960
import static org.elasticsearch.test.ListMatcher.matchesList;
6061
import static org.elasticsearch.test.MapMatcher.assertMap;
@@ -648,6 +649,134 @@ public void testErrorMessageForInvalidIntervalParams() throws IOException {
648649
);
649650
}
650651

652+
public void testErrorMessageForArrayValuesInParams() throws IOException {
653+
ResponseException re = expectThrows(
654+
ResponseException.class,
655+
() -> runEsql(RequestObjectBuilder.jsonBuilder().query("row a = 1 | eval x = ?").params("[{\"n1\": [5, 6, 7]}]"))
656+
);
657+
assertThat(
658+
EntityUtils.toString(re.getResponse().getEntity()),
659+
containsString("Failed to parse params: [1:45] n1=[5, 6, 7] is not supported as a parameter")
660+
);
661+
}
662+
663+
public void testNamedParamsForIdentifierAndIdentifierPatterns() throws IOException {
664+
bulkLoadTestData(10);
665+
// positive
666+
var query = requestObjectBuilder().query(
667+
format(
668+
null,
669+
"from {} | eval x1 = ?n1 | where ?n2 == x1 | stats xx2 = ?fn1(?n3) by ?n4 | keep ?n4, ?n5 | sort ?n4",
670+
testIndexName()
671+
)
672+
)
673+
.params(
674+
"[{\"n1\" : {\"value\" : \"integer\" , \"kind\" : \"identifier\"}},"
675+
+ "{\"n2\" : {\"value\" : \"short\" , \"kind\" : \"identifier\"}}, "
676+
+ "{\"n3\" : {\"value\" : \"double\" , \"kind\" : \"identifier\"}},"
677+
+ "{\"n4\" : {\"value\" : \"boolean\" , \"kind\" : \"identifier\"}}, "
678+
+ "{\"n5\" : {\"value\" : \"xx*\" , \"kind\" : \"pattern\"}}, "
679+
+ "{\"fn1\" : {\"value\" : \"max\" , \"kind\" : \"identifier\"}}]"
680+
);
681+
Map<String, Object> result = runEsql(query);
682+
Map<String, String> colA = Map.of("name", "boolean", "type", "boolean");
683+
Map<String, String> colB = Map.of("name", "xx2", "type", "double");
684+
assertEquals(List.of(colA, colB), result.get("columns"));
685+
assertEquals(List.of(List.of(false, 9.1), List.of(true, 8.1)), result.get("values"));
686+
687+
// missing params
688+
ResponseException re = expectThrows(
689+
ResponseException.class,
690+
() -> runEsqlSync(
691+
requestObjectBuilder().query(
692+
format(
693+
null,
694+
"from {} | eval x1 = ?n1 | where ?n2 == x1 | stats xx2 = max(?n3) by ?n4 | keep ?n4, ?n5 | sort ?n4",
695+
testIndexName()
696+
)
697+
).params("[]")
698+
)
699+
);
700+
String error = re.getMessage();
701+
assertThat(error, containsString("ParsingException"));
702+
assertThat(error, containsString("Unknown query parameter [n1]"));
703+
704+
// param inside backquote is not recognized as a param
705+
Map<String, Integer> commandsWithLineNumber = Map.ofEntries(
706+
entry("eval x1 = `?n1`", 33),
707+
entry("where `?n1` == 1", 29),
708+
entry("stats x = max(n2) by `?n1`", 44),
709+
entry("stats x = max(`?n1`) by n2", 37),
710+
entry("keep `?n1`", 28),
711+
entry("sort `?n1`", 28)
712+
);
713+
for (Map.Entry<String, Integer> command : commandsWithLineNumber.entrySet()) {
714+
re = expectThrows(
715+
ResponseException.class,
716+
() -> runEsqlSync(
717+
requestObjectBuilder().query(format(null, "from {} | {}", testIndexName(), command.getKey()))
718+
.params(
719+
"[{\"n1\" : {\"value\" : \"integer\" , \"kind\" : \"identifier\"}},"
720+
+ "{\"n2\" : {\"value\" : \"short\" , \"kind\" : \"identifier\"}}]"
721+
)
722+
)
723+
);
724+
error = re.getMessage();
725+
assertThat(error, containsString("VerificationException"));
726+
assertThat(error, containsString("line 1:" + command.getValue() + ": Unknown column [?n1]"));
727+
}
728+
729+
commandsWithLineNumber = Map.ofEntries(
730+
entry("rename ?n1 as ?n2", 30),
731+
entry("enrich idx2 ON ?n1 WITH ?n2 = ?n3", 38),
732+
entry("keep ?n1", 28),
733+
entry("drop ?n1", 28)
734+
);
735+
for (Map.Entry<String, Integer> command : commandsWithLineNumber.entrySet()) {
736+
re = expectThrows(
737+
ResponseException.class,
738+
() -> runEsqlSync(
739+
requestObjectBuilder().query(format(null, "from {} | {}", testIndexName(), command.getKey()))
740+
.params(
741+
"[{\"n1\" : {\"value\" : \"`n1`\" , \"kind\" : \"identifier\"}},"
742+
+ "{\"n2\" : {\"value\" : \"`n2`\" , \"kind\" : \"identifier\"}}, "
743+
+ "{\"n3\" : {\"value\" : \"`n3`\" , \"kind\" : \"identifier\"}}]"
744+
)
745+
)
746+
);
747+
error = re.getMessage();
748+
assertThat(error, containsString("VerificationException"));
749+
assertThat(error, containsString("line 1:" + command.getValue() + ": Unknown column [`n1`]"));
750+
}
751+
752+
// param cannot be used as a command name
753+
Map<String, String> paramsAsCommandNames = Map.ofEntries(
754+
entry("eval", "x = 1"),
755+
entry("where", "x == 1"),
756+
entry("stats", "x = count(*)"),
757+
entry("keep", "x"),
758+
entry("drop", "x"),
759+
entry("rename", "x as y"),
760+
entry("sort", "x"),
761+
entry("dissect", "x \"%{foo}\""),
762+
entry("grok", "x \"%{WORD:foo}\""),
763+
entry("enrich", "idx2 ON x"),
764+
entry("mvExpand", "x")
765+
);
766+
for (Map.Entry<String, String> command : paramsAsCommandNames.entrySet()) {
767+
re = expectThrows(
768+
ResponseException.class,
769+
() -> runEsqlSync(
770+
requestObjectBuilder().query(format(null, "from {} | ?cmd {}", testIndexName(), command.getValue()))
771+
.params("[{\"cmd\" : {\"value\" : \"" + command.getKey() + "\", \"kind\" : \"identifier\"}}]")
772+
)
773+
);
774+
error = re.getMessage();
775+
assertThat(error, containsString("ParsingException"));
776+
assertThat(error, containsString("line 1:23: mismatched input '?cmd' expecting {'dissect', 'drop'"));
777+
}
778+
}
779+
651780
public void testErrorMessageForLiteralDateMathOverflow() throws IOException {
652781
List<String> dateMathOverflowExpressions = List.of(
653782
"2147483647 day + 1 day",
@@ -687,14 +816,6 @@ private void assertExceptionForDateMath(String dateMathString, String errorSubst
687816
assertThat(re.getResponse().getStatusLine().getStatusCode(), equalTo(400));
688817
}
689818

690-
public void testErrorMessageForArrayValuesInParams() throws IOException {
691-
ResponseException re = expectThrows(
692-
ResponseException.class,
693-
() -> runEsql(requestObjectBuilder().query("row a = 1 | eval x = ?").params("[{\"n1\": [5, 6, 7]}]"))
694-
);
695-
assertThat(EntityUtils.toString(re.getResponse().getEntity()), containsString("n1=[5, 6, 7] is not supported as a parameter"));
696-
}
697-
698819
public void testComplexFieldNames() throws IOException {
699820
bulkLoadTestData(1);
700821
// catch verification exception, field names not found

x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/EsqlTestUtils.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
import org.elasticsearch.xpack.esql.expression.predicate.operator.comparison.LessThanOrEqual;
5656
import org.elasticsearch.xpack.esql.expression.predicate.operator.comparison.NotEquals;
5757
import org.elasticsearch.xpack.esql.index.EsIndex;
58+
import org.elasticsearch.xpack.esql.parser.QueryParam;
5859
import org.elasticsearch.xpack.esql.plan.logical.Enrich;
5960
import org.elasticsearch.xpack.esql.plan.logical.EsRelation;
6061
import org.elasticsearch.xpack.esql.plan.logical.LogicalPlan;
@@ -119,8 +120,12 @@
119120
import static org.elasticsearch.test.MapMatcher.assertMap;
120121
import static org.elasticsearch.xpack.esql.core.tree.Source.EMPTY;
121122
import static org.elasticsearch.xpack.esql.core.type.DataType.INTEGER;
123+
import static org.elasticsearch.xpack.esql.core.type.DataType.NULL;
122124
import static org.elasticsearch.xpack.esql.core.util.SpatialCoordinateTypes.CARTESIAN;
123125
import static org.elasticsearch.xpack.esql.core.util.SpatialCoordinateTypes.GEO;
126+
import static org.elasticsearch.xpack.esql.parser.ParserUtils.ParamClassification.IDENTIFIER;
127+
import static org.elasticsearch.xpack.esql.parser.ParserUtils.ParamClassification.PATTERN;
128+
import static org.elasticsearch.xpack.esql.parser.ParserUtils.ParamClassification.VALUE;
124129
import static org.hamcrest.Matchers.instanceOf;
125130
import static org.junit.Assert.assertTrue;
126131

@@ -681,4 +686,16 @@ public static WildcardLike wildcardLike(Expression left, String exp) {
681686
public static RLike rlike(Expression left, String exp) {
682687
return new RLike(EMPTY, left, new RLikePattern(exp));
683688
}
689+
690+
public static QueryParam paramAsConstant(String name, Object value) {
691+
return new QueryParam(name, value, DataType.fromJava(value), VALUE);
692+
}
693+
694+
public static QueryParam paramAsIdentifier(String name, Object value) {
695+
return new QueryParam(name, value, NULL, IDENTIFIER);
696+
}
697+
698+
public static QueryParam paramAsPattern(String name, Object value) {
699+
return new QueryParam(name, value, NULL, PATTERN);
700+
}
684701
}

0 commit comments

Comments
 (0)