Skip to content
Open
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
193d8f7
non-correlated subquery in from command
fang-xing-esql Sep 30, 2025
0c5b79d
Merge branch 'main' into subquery-in-from
fang-xing-esql Sep 30, 2025
440e501
Update docs/changelog/135744.yaml
fang-xing-esql Sep 30, 2025
61c7266
Merge branch 'main' into subquery-in-from
fang-xing-esql Sep 30, 2025
20e543d
cleanup
fang-xing-esql Sep 30, 2025
f7d695d
update tests
fang-xing-esql Oct 1, 2025
fb221c9
subquery serialization
fang-xing-esql Oct 1, 2025
a38f6b9
fix predicate push down
fang-xing-esql Oct 2, 2025
8b6db54
add metadata in subquery tests
fang-xing-esql Oct 3, 2025
7f4f372
Merge branch 'main' into subquery-in-from
fang-xing-esql Oct 3, 2025
83353fb
add subquery serialization tests and add comments to each subquery te…
fang-xing-esql Oct 3, 2025
079f403
add telemetry for subquery in from command
fang-xing-esql Oct 3, 2025
99fc31d
Merge branch 'main' into subquery-in-from
fang-xing-esql Oct 3, 2025
c489ab1
[CI] Auto commit changes from spotless
Oct 3, 2025
71d15e1
Merge branch 'main' into subquery-in-from
fang-xing-esql Oct 6, 2025
7cc94a5
create a new rule PushDownFilterAndLimitIntoUnionAll to do predicate …
fang-xing-esql Oct 7, 2025
30c2295
update according to review comments
fang-xing-esql Oct 7, 2025
b31154f
Merge branch 'main' into subquery-in-from
fang-xing-esql Oct 7, 2025
f06b7a2
remove subquery merging in parser, add tests for subqueries with requ…
fang-xing-esql Oct 7, 2025
b170df7
cast counter types to the corresponding normal numeric types
fang-xing-esql Oct 9, 2025
71171e1
Merge branch 'main' into subquery-in-from
fang-xing-esql Oct 9, 2025
b501bc8
stablize tests
fang-xing-esql Oct 9, 2025
9c333d3
Merge branch 'main' into subquery-in-from
fang-xing-esql Oct 9, 2025
1853615
code refactor and remove copy EsqlExecutionInfo
fang-xing-esql Oct 9, 2025
be82a74
handle subquery with fork and full text function better
fang-xing-esql Oct 13, 2025
d672fb8
add capabilities and refactor according to review comments
fang-xing-esql Oct 13, 2025
e776729
Merge branch 'main' into subquery-in-from
fang-xing-esql Oct 13, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions docs/changelog/135744.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pr: 135744
summary: Non-Correlated Subquery in FROM command
area: ES|QL
type: enhancement
issues: []
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@ public abstract class Attribute extends NamedExpression {
/**
* Changing this will break bwc with 8.15, see {@link FieldAttribute#fieldName()}.
*/
protected static final String SYNTHETIC_ATTRIBUTE_NAME_PREFIX = "$$";
public static final String SYNTHETIC_ATTRIBUTE_NAME_PREFIX = "$$";

public static final String SYNTHETIC_ATTRIBUTE_NAME_SEPARATOR = "$";

private static final TransportVersion ESQL_QUALIFIERS_IN_ATTRIBUTES = TransportVersion.fromName("esql_qualifiers_in_attributes");

Expand Down Expand Up @@ -77,7 +79,7 @@ public Attribute(
}

public static String rawTemporaryName(String... parts) {
var name = String.join("$", parts);
var name = String.join(SYNTHETIC_ATTRIBUTE_NAME_SEPARATOR, parts);
return name.isEmpty() || name.startsWith(SYNTHETIC_ATTRIBUTE_NAME_PREFIX) ? name : SYNTHETIC_ATTRIBUTE_NAME_PREFIX + name;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
import static org.elasticsearch.xpack.esql.action.EsqlCapabilities.Cap.JOIN_LOOKUP_V12;
import static org.elasticsearch.xpack.esql.action.EsqlCapabilities.Cap.JOIN_PLANNING_V1;
import static org.elasticsearch.xpack.esql.action.EsqlCapabilities.Cap.METADATA_FIELDS_REMOTE_TEST;
import static org.elasticsearch.xpack.esql.action.EsqlCapabilities.Cap.SUBQUERY_IN_FROM_COMMAND;
import static org.elasticsearch.xpack.esql.action.EsqlCapabilities.Cap.UNMAPPED_FIELDS;
import static org.elasticsearch.xpack.esql.qa.rest.RestEsqlTestCase.hasCapabilities;
import static org.mockito.ArgumentMatchers.any;
Expand Down Expand Up @@ -172,6 +173,12 @@ protected void shouldSkipTest(String testName) throws IOException {
hasCapabilities(adminClient(), List.of(ENABLE_FORK_FOR_REMOTE_INDICES.capabilityName()))
);
}
// Subqueries in FROM are not fully tested in CCS yet
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When there is subquery exists in the query convertToRemoteIndices doesn't generate a correct remote index pattern yet, the query becomes invalid. Subqueries are not fully tested in CCS yet, working on it as a follow up.

// And convertToRemoteIndices does not generate correct queries with subqueries in the FROM command yet
assumeFalse(
"Subqueries in FROM command not yet supported in CCS",
testCase.requiredCapabilities.contains(SUBQUERY_IN_FROM_COMMAND.capabilityName())
);
}

private TestFeatureService remoteFeaturesService() throws IOException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1336,6 +1336,89 @@ public void testTopLevelFilterBoolMerged() throws IOException {
}
}

public void testTopLevelFilterWithSubqueriesInFromCommand() throws IOException {
assumeTrue("subqueries in from command", EsqlCapabilities.Cap.SUBQUERY_IN_FROM_COMMAND.isEnabled());

bulkLoadTestData(10);

String query = format(null, "FROM {} , (FROM {} | WHERE integer < 8) | STATS count(*)", testIndexName(), testIndexName());

RequestObjectBuilder builder = requestObjectBuilder().filter(b -> {
b.startObject("range");
{
b.startObject("integer").field("gte", "5").endObject();
}
b.endObject();
}).query(query);

Map<String, Object> result = runEsql(builder);
assertResultMap(result, matchesList().item(matchesMap().entry("name", "count(*)").entry("type", "long")), List.of(List.of(8)));
}

public void testNestedSubqueries() throws IOException {
assumeTrue("subqueries in from command", EsqlCapabilities.Cap.SUBQUERY_IN_FROM_COMMAND.isEnabled());

bulkLoadTestData(10);

ResponseException re = expectThrows(
ResponseException.class,
() -> runEsqlSync(
requestObjectBuilder().query(
format(
null,
"from {}, (from {}, (from {} | where integer > 1) | where integer < 8) | stats count(*)",
testIndexName(),
testIndexName(),
testIndexName()
)
)
)
);
String error = re.getMessage().replaceAll("\\\\\n\s+\\\\", "");
assertThat(error, containsString("VerificationException"));
assertThat(error, containsString("Nested subqueries are not supported"));
}

public void testSubqueryWithFork() throws IOException {
assumeTrue("subqueries in from command", EsqlCapabilities.Cap.SUBQUERY_IN_FROM_COMMAND.isEnabled());

bulkLoadTestData(10);

ResponseException re = expectThrows(
ResponseException.class,
() -> runEsqlSync(
requestObjectBuilder().query(
format(
null,
"from {}, (from {} | where integer > 1) | fork (where long > 2) (where ip == \"127.0.0.1\") | stats count(*)",
testIndexName(),
testIndexName()
)
)
)
);
String error = re.getMessage().replaceAll("\\\\\n\s+\\\\", "");
assertThat(error, containsString("VerificationException"));
assertThat(error, containsString("FORK after subquery is not supported"));

re = expectThrows(
ResponseException.class,
() -> runEsqlSync(
requestObjectBuilder().query(
format(
null,
"from {}, (from {} | where integer > 1 | fork (where long > 2) ( where ip == \"127.0.0.1\")) | stats count(*)",
testIndexName(),
testIndexName()
)
)
)
);
error = re.getMessage().replaceAll("\\\\\n\s+\\\\", "");
assertThat(error, containsString("VerificationException"));
assertThat(error, containsString("FORK inside subquery is not supported"));
}

private static String queryWithComplexFieldNames(int field) {
StringBuilder query = new StringBuilder();
query.append(" | keep ").append(randomAlphaOfLength(10)).append(1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ protected void shouldSkipTest(String testName) throws IOException {
testCase.requiredCapabilities.contains(UNMAPPED_FIELDS.capabilityName())
);

assumeFalse(
"Tests using subqueries are skipped since we don't support nested subqueries",
testCase.requiredCapabilities.contains(SUBQUERY_IN_FROM_COMMAND.capabilityName())
);

assumeTrue("Cluster needs to support FORK", hasCapabilities(adminClient(), List.of(FORK_V9.capabilityName())));
}
}
Loading