Skip to content

Commit 242b841

Browse files
authored
Disallow CCS with lookup join (#120277)
1 parent 52e0f21 commit 242b841

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.common.Failure;
2022
import org.elasticsearch.xpack.esql.core.expression.Alias;
@@ -527,6 +529,13 @@ public PlanFactory visitJoinCommand(EsqlBaseParser.JoinCommandContext ctx) {
527529
if (rightPattern.contains(WILDCARD)) {
528530
throw new ParsingException(source(target), "invalid index pattern [{}], * is not allowed in LOOKUP JOIN", rightPattern);
529531
}
532+
if (RemoteClusterAware.isRemoteIndexName(rightPattern)) {
533+
throw new ParsingException(
534+
source(target),
535+
"invalid index pattern [{}], remote clusters are not supported in LOOKUP JOIN",
536+
rightPattern
537+
);
538+
}
530539

531540
UnresolvedRelation right = new UnresolvedRelation(
532541
source(target),
@@ -557,6 +566,20 @@ public PlanFactory visitJoinCommand(EsqlBaseParser.JoinCommandContext ctx) {
557566
throw new ParsingException(source, "JOIN ON clause only supports one field at the moment, found [{}]", matchFieldsCount);
558567
}
559568

560-
return p -> new LookupJoin(source, p, right, joinFields);
569+
return p -> {
570+
p.forEachUp(UnresolvedRelation.class, r -> {
571+
for (var leftPattern : Strings.splitStringByCommaToArray(r.indexPattern().indexPattern())) {
572+
if (RemoteClusterAware.isRemoteIndexName(leftPattern)) {
573+
throw new ParsingException(
574+
source(target),
575+
"invalid index pattern [{}], remote clusters are not supported in LOOKUP JOIN",
576+
r.indexPattern().indexPattern()
577+
);
578+
}
579+
}
580+
});
581+
582+
return new LookupJoin(source, p, right, joinFields);
583+
};
561584
}
562585
}

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))));
@@ -2067,41 +2068,41 @@ private void assertStringAsLookupIndexPattern(String string, String statement) {
20672068
assertThat(tableName.fold(FoldContext.small()), equalTo(string));
20682069
}
20692070

2070-
public void testIdPatternUnquoted() throws Exception {
2071+
public void testIdPatternUnquoted() {
20712072
var string = "regularString";
20722073
assertThat(breakIntoFragments(string), contains(string));
20732074
}
20742075

2075-
public void testIdPatternQuoted() throws Exception {
2076+
public void testIdPatternQuoted() {
20762077
var string = "`escaped string`";
20772078
assertThat(breakIntoFragments(string), contains(string));
20782079
}
20792080

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

2085-
public void testIdPatternUnquotedAndQuoted() throws Exception {
2086+
public void testIdPatternUnquotedAndQuoted() {
20862087
var string = "this`is`a`mix`of`ids`";
20872088
assertThat(breakIntoFragments(string), contains("this", "`is`", "a", "`mix`", "of", "`ids`"));
20882089
}
20892090

2090-
public void testIdPatternQuotedTraling() throws Exception {
2091+
public void testIdPatternQuotedTraling() {
20912092
var string = "`foo`*";
20922093
assertThat(breakIntoFragments(string), contains("`foo`", "*"));
20932094
}
20942095

2095-
public void testIdPatternWithDoubleQuotedStrings() throws Exception {
2096+
public void testIdPatternWithDoubleQuotedStrings() {
20962097
var string = "`this``is`a`quoted `` string``with`backticks";
20972098
assertThat(breakIntoFragments(string), contains("`this``is`", "a", "`quoted `` string``with`", "backticks"));
20982099
}
20992100

2100-
public void testSpaceNotAllowedInIdPattern() throws Exception {
2101+
public void testSpaceNotAllowedInIdPattern() {
21012102
expectError("ROW a = 1| RENAME a AS this is `not okay`", "mismatched input 'is' expecting {<EOF>, '|', ',', '.'}");
21022103
}
21032104

2104-
public void testSpaceNotAllowedInIdPatternKeep() throws Exception {
2105+
public void testSpaceNotAllowedInIdPatternKeep() {
21052106
expectError("ROW a = 1, b = 1| KEEP a b", "extraneous input 'b'");
21062107
}
21072108

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

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

2948-
var plan = statement("FROM " + basePattern + " | " + type + " JOIN " + joinPattern + " ON " + onField);
2956+
var plan = statement("FROM " + basePattern + " | LOOKUP JOIN " + joinPattern + " ON " + onField);
29492957

29502958
var join = as(plan, LookupJoin.class);
29512959
assertThat(as(join.left(), UnresolvedRelation.class).indexPattern().indexPattern(), equalTo(unquoteIndexPattern(basePattern)));
@@ -2958,10 +2966,31 @@ public void testValidJoinPattern() {
29582966
}
29592967

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

0 commit comments

Comments
 (0)