Skip to content

Commit 90569c6

Browse files
authored
Disallow CCS with lookup join (#120277) (#120882)
1 parent b074d13 commit 90569c6

File tree

2 files changed

+76
-24
lines changed

2 files changed

+76
-24
lines changed

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/LogicalPlanBuilder.java

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,12 @@
1111
import org.antlr.v4.runtime.Token;
1212
import org.antlr.v4.runtime.tree.ParseTree;
1313
import org.elasticsearch.Build;
14+
import org.elasticsearch.common.Strings;
1415
import org.elasticsearch.core.Tuple;
1516
import org.elasticsearch.dissect.DissectException;
1617
import org.elasticsearch.dissect.DissectParser;
1718
import org.elasticsearch.index.IndexMode;
19+
import org.elasticsearch.transport.RemoteClusterAware;
1820
import org.elasticsearch.xpack.esql.VerificationException;
1921
import org.elasticsearch.xpack.esql.action.EsqlCapabilities;
2022
import org.elasticsearch.xpack.esql.common.Failure;
@@ -545,6 +547,13 @@ public PlanFactory visitJoinCommand(EsqlBaseParser.JoinCommandContext ctx) {
545547
if (rightPattern.contains(WILDCARD)) {
546548
throw new ParsingException(source(target), "invalid index pattern [{}], * is not allowed in LOOKUP JOIN", rightPattern);
547549
}
550+
if (RemoteClusterAware.isRemoteIndexName(rightPattern)) {
551+
throw new ParsingException(
552+
source(target),
553+
"invalid index pattern [{}], remote clusters are not supported in LOOKUP JOIN",
554+
rightPattern
555+
);
556+
}
548557

549558
UnresolvedRelation right = new UnresolvedRelation(
550559
source(target),
@@ -575,6 +584,20 @@ public PlanFactory visitJoinCommand(EsqlBaseParser.JoinCommandContext ctx) {
575584
throw new ParsingException(source, "JOIN ON clause only supports one field at the moment, found [{}]", matchFieldsCount);
576585
}
577586

578-
return p -> new LookupJoin(source, p, right, joinFields);
587+
return p -> {
588+
p.forEachUp(UnresolvedRelation.class, r -> {
589+
for (var leftPattern : Strings.splitStringByCommaToArray(r.indexPattern().indexPattern())) {
590+
if (RemoteClusterAware.isRemoteIndexName(leftPattern)) {
591+
throw new ParsingException(
592+
source(target),
593+
"invalid index pattern [{}], remote clusters are not supported in LOOKUP JOIN",
594+
r.indexPattern().indexPattern()
595+
);
596+
}
597+
}
598+
});
599+
600+
return new LookupJoin(source, p, right, joinFields);
601+
};
579602
}
580603
}

x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/parser/StatementParserTests.java

Lines changed: 52 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@
7878
import static org.elasticsearch.xpack.esql.EsqlTestUtils.paramAsIdentifier;
7979
import static org.elasticsearch.xpack.esql.EsqlTestUtils.paramAsPattern;
8080
import static org.elasticsearch.xpack.esql.EsqlTestUtils.referenceAttribute;
81+
import static org.elasticsearch.xpack.esql.IdentifierGenerator.Features.CROSS_CLUSTER;
8182
import static org.elasticsearch.xpack.esql.IdentifierGenerator.Features.WILDCARD_PATTERN;
8283
import static org.elasticsearch.xpack.esql.IdentifierGenerator.randomIndexPattern;
8384
import static org.elasticsearch.xpack.esql.IdentifierGenerator.randomIndexPatterns;
@@ -307,18 +308,18 @@ public void testStatsWithoutGroups() {
307308
);
308309
}
309310

310-
public void testStatsWithoutAggs() throws Exception {
311+
public void testStatsWithoutAggs() {
311312
assertEquals(
312313
new Aggregate(EMPTY, PROCESSING_CMD_INPUT, Aggregate.AggregateType.STANDARD, List.of(attribute("a")), List.of(attribute("a"))),
313314
processingCommand("stats by a")
314315
);
315316
}
316317

317-
public void testStatsWithoutAggsOrGroup() throws Exception {
318+
public void testStatsWithoutAggsOrGroup() {
318319
expectError("from text | stats", "At least one aggregation or grouping expression required in [stats]");
319320
}
320321

321-
public void testAggsWithGroupKeyAsAgg() throws Exception {
322+
public void testAggsWithGroupKeyAsAgg() {
322323
var queries = new String[] { """
323324
row a = 1, b = 2
324325
| stats a by a
@@ -339,7 +340,7 @@ public void testAggsWithGroupKeyAsAgg() throws Exception {
339340
}
340341
}
341342

342-
public void testStatsWithGroupKeyAndAggFilter() throws Exception {
343+
public void testStatsWithGroupKeyAndAggFilter() {
343344
var a = attribute("a");
344345
var f = new UnresolvedFunction(EMPTY, "min", DEFAULT, List.of(a));
345346
var filter = new Alias(EMPTY, "min(a) where a > 1", new FilteredExpression(EMPTY, f, new GreaterThan(EMPTY, a, integer(1))));
@@ -349,7 +350,7 @@ public void testStatsWithGroupKeyAndAggFilter() throws Exception {
349350
);
350351
}
351352

352-
public void testStatsWithGroupKeyAndMixedAggAndFilter() throws Exception {
353+
public void testStatsWithGroupKeyAndMixedAggAndFilter() {
353354
var a = attribute("a");
354355
var min = new UnresolvedFunction(EMPTY, "min", DEFAULT, List.of(a));
355356
var max = new UnresolvedFunction(EMPTY, "max", DEFAULT, List.of(a));
@@ -384,7 +385,7 @@ public void testStatsWithGroupKeyAndMixedAggAndFilter() throws Exception {
384385
);
385386
}
386387

387-
public void testStatsWithoutGroupKeyMixedAggAndFilter() throws Exception {
388+
public void testStatsWithoutGroupKeyMixedAggAndFilter() {
388389
var a = attribute("a");
389390
var f = new UnresolvedFunction(EMPTY, "min", DEFAULT, List.of(a));
390391
var filter = new Alias(EMPTY, "min(a) where a > 1", new FilteredExpression(EMPTY, f, new GreaterThan(EMPTY, a, integer(1))));
@@ -2073,41 +2074,41 @@ private void assertStringAsLookupIndexPattern(String string, String statement) {
20732074
assertThat(tableName.fold(FoldContext.small()), equalTo(string));
20742075
}
20752076

2076-
public void testIdPatternUnquoted() throws Exception {
2077+
public void testIdPatternUnquoted() {
20772078
var string = "regularString";
20782079
assertThat(breakIntoFragments(string), contains(string));
20792080
}
20802081

2081-
public void testIdPatternQuoted() throws Exception {
2082+
public void testIdPatternQuoted() {
20822083
var string = "`escaped string`";
20832084
assertThat(breakIntoFragments(string), contains(string));
20842085
}
20852086

2086-
public void testIdPatternQuotedWithDoubleBackticks() throws Exception {
2087+
public void testIdPatternQuotedWithDoubleBackticks() {
20872088
var string = "`escaped``string`";
20882089
assertThat(breakIntoFragments(string), contains(string));
20892090
}
20902091

2091-
public void testIdPatternUnquotedAndQuoted() throws Exception {
2092+
public void testIdPatternUnquotedAndQuoted() {
20922093
var string = "this`is`a`mix`of`ids`";
20932094
assertThat(breakIntoFragments(string), contains("this", "`is`", "a", "`mix`", "of", "`ids`"));
20942095
}
20952096

2096-
public void testIdPatternQuotedTraling() throws Exception {
2097+
public void testIdPatternQuotedTraling() {
20972098
var string = "`foo`*";
20982099
assertThat(breakIntoFragments(string), contains("`foo`", "*"));
20992100
}
21002101

2101-
public void testIdPatternWithDoubleQuotedStrings() throws Exception {
2102+
public void testIdPatternWithDoubleQuotedStrings() {
21022103
var string = "`this``is`a`quoted `` string``with`backticks";
21032104
assertThat(breakIntoFragments(string), contains("`this``is`", "a", "`quoted `` string``with`", "backticks"));
21042105
}
21052106

2106-
public void testSpaceNotAllowedInIdPattern() throws Exception {
2107+
public void testSpaceNotAllowedInIdPattern() {
21072108
expectError("ROW a = 1| RENAME a AS this is `not okay`", "mismatched input 'is' expecting {<EOF>, '|', ',', '.'}");
21082109
}
21092110

2110-
public void testSpaceNotAllowedInIdPatternKeep() throws Exception {
2111+
public void testSpaceNotAllowedInIdPatternKeep() {
21112112
expectError("ROW a = 1, b = 1| KEEP a b", "extraneous input 'b'");
21122113
}
21132114

@@ -2938,13 +2939,20 @@ public void testNamedFunctionArgumentWithUnsupportedNamedParameterTypes() {
29382939
}
29392940
}
29402941

2941-
public void testValidJoinPattern() {
2942+
public void testValidFromPattern() {
29422943
var basePattern = randomIndexPatterns();
2943-
var joinPattern = randomIndexPattern(without(WILDCARD_PATTERN));
2944+
2945+
var plan = statement("FROM " + basePattern);
2946+
2947+
assertThat(as(plan, UnresolvedRelation.class).indexPattern().indexPattern(), equalTo(unquoteIndexPattern(basePattern)));
2948+
}
2949+
2950+
public void testValidJoinPattern() {
2951+
var basePattern = randomIndexPatterns(without(CROSS_CLUSTER));
2952+
var joinPattern = randomIndexPattern(without(WILDCARD_PATTERN), without(CROSS_CLUSTER));
29442953
var onField = randomIdentifier();
2945-
var type = randomFrom("", "LOOKUP ");
29462954

2947-
var plan = statement("FROM " + basePattern + " | " + type + " JOIN " + joinPattern + " ON " + onField);
2955+
var plan = statement("FROM " + basePattern + " | LOOKUP JOIN " + joinPattern + " ON " + onField);
29482956

29492957
var join = as(plan, LookupJoin.class);
29502958
assertThat(as(join.left(), UnresolvedRelation.class).indexPattern().indexPattern(), equalTo(unquoteIndexPattern(basePattern)));
@@ -2957,10 +2965,31 @@ public void testValidJoinPattern() {
29572965
}
29582966

29592967
public void testInvalidJoinPatterns() {
2960-
var joinPattern = randomIndexPattern(WILDCARD_PATTERN);
2961-
expectError(
2962-
"FROM " + randomIndexPatterns() + " | JOIN " + joinPattern + " ON " + randomIdentifier(),
2963-
"invalid index pattern [" + unquoteIndexPattern(joinPattern) + "], * is not allowed in LOOKUP JOIN"
2964-
);
2968+
{
2969+
// wildcard
2970+
var joinPattern = randomIndexPattern(WILDCARD_PATTERN, without(CROSS_CLUSTER));
2971+
expectError(
2972+
"FROM " + randomIndexPatterns() + " | LOOKUP JOIN " + joinPattern + " ON " + randomIdentifier(),
2973+
"invalid index pattern [" + unquoteIndexPattern(joinPattern) + "], * is not allowed in LOOKUP JOIN"
2974+
);
2975+
}
2976+
{
2977+
// remote cluster on the right
2978+
var fromPatterns = randomIndexPatterns(without(CROSS_CLUSTER));
2979+
var joinPattern = randomIndexPattern(CROSS_CLUSTER, without(WILDCARD_PATTERN));
2980+
expectError(
2981+
"FROM " + fromPatterns + " | LOOKUP JOIN " + joinPattern + " ON " + randomIdentifier(),
2982+
"invalid index pattern [" + unquoteIndexPattern(joinPattern) + "], remote clusters are not supported in LOOKUP JOIN"
2983+
);
2984+
}
2985+
{
2986+
// remote cluster on the left
2987+
var fromPatterns = randomIndexPatterns(CROSS_CLUSTER);
2988+
var joinPattern = randomIndexPattern(without(CROSS_CLUSTER), without(WILDCARD_PATTERN));
2989+
expectError(
2990+
"FROM " + fromPatterns + " | LOOKUP JOIN " + joinPattern + " ON " + randomIdentifier(),
2991+
"invalid index pattern [" + unquoteIndexPattern(fromPatterns) + "], remote clusters are not supported in LOOKUP JOIN"
2992+
);
2993+
}
29652994
}
29662995
}

0 commit comments

Comments
 (0)