-
Notifications
You must be signed in to change notification settings - Fork 25.6k
Disallow CCS with lookup join #120277
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Disallow CCS with lookup join #120277
Changes from 8 commits
1b99a4d
b8cf1b3
b1a0280
5f55608
57a0df6
c9b077e
c6be044
6a94eaf
d283968
66dd33c
343d104
416a8fc
a6aa610
59b78b7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| pr: 120277 | ||
| summary: Disallow CCS with lookup join | ||
| area: ES|QL | ||
| type: enhancement | ||
| issues: [] | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -15,6 +15,7 @@ | |
| import org.elasticsearch.dissect.DissectException; | ||
| import org.elasticsearch.dissect.DissectParser; | ||
| import org.elasticsearch.index.IndexMode; | ||
| import org.elasticsearch.transport.RemoteClusterAware; | ||
| import org.elasticsearch.xpack.esql.VerificationException; | ||
| import org.elasticsearch.xpack.esql.common.Failure; | ||
| import org.elasticsearch.xpack.esql.core.expression.Alias; | ||
|
|
@@ -523,9 +524,15 @@ public PlanFactory visitJoinCommand(EsqlBaseParser.JoinCommandContext ctx) { | |
| } | ||
|
|
||
| var target = ctx.joinTarget(); | ||
| var rightPattern = visitIdentifier(target.index); | ||
|
|
||
| if (RemoteClusterAware.isRemoteIndexName(rightPattern)) { | ||
| throw new ParsingException(source(target), "LOOKUP JOIN does not support remote cluster indices [{}]", rightPattern); | ||
| } | ||
|
||
|
|
||
| UnresolvedRelation right = new UnresolvedRelation( | ||
| source(target), | ||
| new TableIdentifier(source(target.index), null, visitIdentifier(target.index)), | ||
| new TableIdentifier(source(target.index), null, rightPattern), | ||
| false, | ||
| emptyList(), | ||
| IndexMode.LOOKUP, | ||
|
|
@@ -552,6 +559,18 @@ public PlanFactory visitJoinCommand(EsqlBaseParser.JoinCommandContext ctx) { | |
| throw new ParsingException(source, "JOIN ON clause only supports one field at the moment, found [{}]", matchFieldsCount); | ||
| } | ||
|
|
||
| return p -> new LookupJoin(source, p, right, joinFields); | ||
| return p -> { | ||
| p.forEachUp(UnresolvedRelation.class, r -> { | ||
| if (RemoteClusterAware.isRemoteIndexName(r.table().index())) { | ||
|
||
| throw new ParsingException( | ||
| source(target), | ||
| "LOOKUP JOIN does not support remote cluster indices [{}]", | ||
| r.table().index() | ||
| ); | ||
| } | ||
| }); | ||
|
|
||
| return new LookupJoin(source, p, right, joinFields); | ||
| }; | ||
| } | ||
| } | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. One more test case suggestion: comma-separated list of index patterns, some of which are remote. E.g. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -300,18 +300,18 @@ public void testStatsWithoutGroups() { | |
| ); | ||
| } | ||
|
|
||
| public void testStatsWithoutAggs() throws Exception { | ||
| public void testStatsWithoutAggs() { | ||
| assertEquals( | ||
| new Aggregate(EMPTY, PROCESSING_CMD_INPUT, Aggregate.AggregateType.STANDARD, List.of(attribute("a")), List.of(attribute("a"))), | ||
| processingCommand("stats by a") | ||
| ); | ||
| } | ||
|
|
||
| public void testStatsWithoutAggsOrGroup() throws Exception { | ||
| public void testStatsWithoutAggsOrGroup() { | ||
| expectError("from text | stats", "At least one aggregation or grouping expression required in [stats]"); | ||
| } | ||
|
|
||
| public void testAggsWithGroupKeyAsAgg() throws Exception { | ||
| public void testAggsWithGroupKeyAsAgg() { | ||
| var queries = new String[] { """ | ||
| row a = 1, b = 2 | ||
| | stats a by a | ||
|
|
@@ -332,7 +332,7 @@ public void testAggsWithGroupKeyAsAgg() throws Exception { | |
| } | ||
| } | ||
|
|
||
| public void testStatsWithGroupKeyAndAggFilter() throws Exception { | ||
| public void testStatsWithGroupKeyAndAggFilter() { | ||
| var a = attribute("a"); | ||
| var f = new UnresolvedFunction(EMPTY, "min", DEFAULT, List.of(a)); | ||
| var filter = new Alias(EMPTY, "min(a) where a > 1", new FilteredExpression(EMPTY, f, new GreaterThan(EMPTY, a, integer(1)))); | ||
|
|
@@ -342,7 +342,7 @@ public void testStatsWithGroupKeyAndAggFilter() throws Exception { | |
| ); | ||
| } | ||
|
|
||
| public void testStatsWithGroupKeyAndMixedAggAndFilter() throws Exception { | ||
| public void testStatsWithGroupKeyAndMixedAggAndFilter() { | ||
| var a = attribute("a"); | ||
| var min = new UnresolvedFunction(EMPTY, "min", DEFAULT, List.of(a)); | ||
| var max = new UnresolvedFunction(EMPTY, "max", DEFAULT, List.of(a)); | ||
|
|
@@ -377,7 +377,7 @@ public void testStatsWithGroupKeyAndMixedAggAndFilter() throws Exception { | |
| ); | ||
| } | ||
|
|
||
| public void testStatsWithoutGroupKeyMixedAggAndFilter() throws Exception { | ||
| public void testStatsWithoutGroupKeyMixedAggAndFilter() { | ||
| var a = attribute("a"); | ||
| var f = new UnresolvedFunction(EMPTY, "min", DEFAULT, List.of(a)); | ||
| var filter = new Alias(EMPTY, "min(a) where a > 1", new FilteredExpression(EMPTY, f, new GreaterThan(EMPTY, a, integer(1)))); | ||
|
|
@@ -2060,41 +2060,41 @@ private void assertStringAsLookupIndexPattern(String string, String statement) { | |
| assertThat(tableName.fold(FoldContext.small()), equalTo(string)); | ||
| } | ||
|
|
||
| public void testIdPatternUnquoted() throws Exception { | ||
| public void testIdPatternUnquoted() { | ||
| var string = "regularString"; | ||
| assertThat(breakIntoFragments(string), contains(string)); | ||
| } | ||
|
|
||
| public void testIdPatternQuoted() throws Exception { | ||
| public void testIdPatternQuoted() { | ||
| var string = "`escaped string`"; | ||
| assertThat(breakIntoFragments(string), contains(string)); | ||
| } | ||
|
|
||
| public void testIdPatternQuotedWithDoubleBackticks() throws Exception { | ||
| public void testIdPatternQuotedWithDoubleBackticks() { | ||
| var string = "`escaped``string`"; | ||
| assertThat(breakIntoFragments(string), contains(string)); | ||
| } | ||
|
|
||
| public void testIdPatternUnquotedAndQuoted() throws Exception { | ||
| public void testIdPatternUnquotedAndQuoted() { | ||
| var string = "this`is`a`mix`of`ids`"; | ||
| assertThat(breakIntoFragments(string), contains("this", "`is`", "a", "`mix`", "of", "`ids`")); | ||
| } | ||
|
|
||
| public void testIdPatternQuotedTraling() throws Exception { | ||
| public void testIdPatternQuotedTraling() { | ||
| var string = "`foo`*"; | ||
| assertThat(breakIntoFragments(string), contains("`foo`", "*")); | ||
| } | ||
|
|
||
| public void testIdPatternWithDoubleQuotedStrings() throws Exception { | ||
| public void testIdPatternWithDoubleQuotedStrings() { | ||
| var string = "`this``is`a`quoted `` string``with`backticks"; | ||
| assertThat(breakIntoFragments(string), contains("`this``is`", "a", "`quoted `` string``with`", "backticks")); | ||
| } | ||
|
|
||
| public void testSpaceNotAllowedInIdPattern() throws Exception { | ||
| public void testSpaceNotAllowedInIdPattern() { | ||
| expectError("ROW a = 1| RENAME a AS this is `not okay`", "mismatched input 'is' expecting {<EOF>, '|', ',', '.'}"); | ||
| } | ||
|
|
||
| public void testSpaceNotAllowedInIdPatternKeep() throws Exception { | ||
| public void testSpaceNotAllowedInIdPatternKeep() { | ||
| expectError("ROW a = 1, b = 1| KEEP a b", "extraneous input 'b'"); | ||
| } | ||
|
|
||
|
|
@@ -2939,4 +2939,14 @@ public void testNamedFunctionArgumentWithUnsupportedNamedParameterTypes() { | |
| ); | ||
| } | ||
| } | ||
|
|
||
| public void testRemoteLookupJoin() { | ||
| expectError("FROM remote:left | LOOKUP JOIN right ON field", "LOOKUP JOIN does not support remote cluster indices [remote:left]"); | ||
|
||
| expectError( | ||
| "FROM left | LOOKUP JOIN `remote:right` ON field", | ||
| "LOOKUP JOIN does not support remote cluster indices [remote:right]" | ||
| ); | ||
| // TODO ES-10559 this should be replaced with a proper error message once grammar allows indexPattern as joinTarget | ||
| expectError("FROM my-index | LOOKUP JOIN remote:languages_lookup ON language_code", "line 1:35: token recognition error at: ':'"); | ||
|
||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: I'd declare this as
non-issueand would remove the changelog. It's not really an enhancement, anyway :)