From def34ff93aff9ca1fb5adce87626e10b1a79cf15 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20FOUCRET?=
Date: Mon, 18 Nov 2024 09:04:16 +0100
Subject: [PATCH] KQL query nested field support (#116467)
---
.../index/query/NestedQueryBuilder.java | 7 +
x-pack/plugin/kql/src/main/antlr/KqlBase.g4 | 19 +-
.../plugin/kql/src/main/java/module-info.java | 1 +
.../xpack/kql/parser/KqlAstBuilder.java | 85 ++-
.../xpack/kql/parser/KqlBase.interp | 5 +-
.../xpack/kql/parser/KqlBaseBaseListener.java | 48 ++
.../xpack/kql/parser/KqlBaseBaseVisitor.java | 28 +
.../xpack/kql/parser/KqlBaseListener.java | 44 ++
.../xpack/kql/parser/KqlBaseParser.java | 669 +++++++++++++-----
.../xpack/kql/parser/KqlBaseVisitor.java | 26 +
.../xpack/kql/parser/KqlParsingContext.java | 52 +-
.../kql/parser/AbstractKqlParserTestCase.java | 2 -
.../kql/parser/KqlNestedFieldQueryTests.java | 297 ++++++++
.../kql/parser/KqlParserExistsQueryTests.java | 20 +-
.../kql/src/test/resources/supported-queries | 7 -
.../src/test/resources/unsupported-queries | 14 +
.../test/kql/50_kql_nested_fields_query.yml | 218 ++++++
17 files changed, 1333 insertions(+), 209 deletions(-)
create mode 100644 x-pack/plugin/kql/src/test/java/org/elasticsearch/xpack/kql/parser/KqlNestedFieldQueryTests.java
create mode 100644 x-pack/plugin/kql/src/yamlRestTest/resources/rest-api-spec/test/kql/50_kql_nested_fields_query.yml
diff --git a/server/src/main/java/org/elasticsearch/index/query/NestedQueryBuilder.java b/server/src/main/java/org/elasticsearch/index/query/NestedQueryBuilder.java
index 55642ccf0275..94829356af82 100644
--- a/server/src/main/java/org/elasticsearch/index/query/NestedQueryBuilder.java
+++ b/server/src/main/java/org/elasticsearch/index/query/NestedQueryBuilder.java
@@ -112,6 +112,13 @@ public QueryBuilder query() {
return query;
}
+ /**
+ * Returns path to the searched nested object.
+ */
+ public String path() {
+ return path;
+ }
+
/**
* Returns inner hit definition in the scope of this query and reusing the defined type and query.
*/
diff --git a/x-pack/plugin/kql/src/main/antlr/KqlBase.g4 b/x-pack/plugin/kql/src/main/antlr/KqlBase.g4
index da015b699cb1..739fa5eb0c6e 100644
--- a/x-pack/plugin/kql/src/main/antlr/KqlBase.g4
+++ b/x-pack/plugin/kql/src/main/antlr/KqlBase.g4
@@ -46,9 +46,26 @@ notQuery:
;
nestedQuery
- : fieldName COLON LEFT_CURLY_BRACKET query RIGHT_CURLY_BRACKET
+ : fieldName COLON LEFT_CURLY_BRACKET nestedSubQuery RIGHT_CURLY_BRACKET
;
+nestedSubQuery
+ : nestedSubQuery operator=(AND|OR) nestedSubQuery #booleanNestedQuery
+ | nestedSimpleSubQuery #defaultNestedQuery
+ ;
+
+nestedSimpleSubQuery
+ : notQuery
+ | nestedQuery
+ | matchAllQuery
+ | nestedParenthesizedQuery
+ | existsQuery
+ | rangeQuery
+ | fieldQuery;
+
+nestedParenthesizedQuery
+ : LEFT_PARENTHESIS nestedSubQuery RIGHT_PARENTHESIS;
+
matchAllQuery
: (WILDCARD COLON)? WILDCARD
;
diff --git a/x-pack/plugin/kql/src/main/java/module-info.java b/x-pack/plugin/kql/src/main/java/module-info.java
index 41e51033b9c7..e3bb6fb99bbd 100644
--- a/x-pack/plugin/kql/src/main/java/module-info.java
+++ b/x-pack/plugin/kql/src/main/java/module-info.java
@@ -13,6 +13,7 @@
requires org.apache.lucene.queryparser;
requires org.elasticsearch.logging;
requires org.apache.lucene.core;
+ requires org.apache.lucene.join;
exports org.elasticsearch.xpack.kql;
exports org.elasticsearch.xpack.kql.parser;
diff --git a/x-pack/plugin/kql/src/main/java/org/elasticsearch/xpack/kql/parser/KqlAstBuilder.java b/x-pack/plugin/kql/src/main/java/org/elasticsearch/xpack/kql/parser/KqlAstBuilder.java
index 67d7da0381d6..6b7365a365bb 100644
--- a/x-pack/plugin/kql/src/main/java/org/elasticsearch/xpack/kql/parser/KqlAstBuilder.java
+++ b/x-pack/plugin/kql/src/main/java/org/elasticsearch/xpack/kql/parser/KqlAstBuilder.java
@@ -9,6 +9,7 @@
import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.Token;
+import org.apache.lucene.search.join.ScoreMode;
import org.elasticsearch.common.regex.Regex;
import org.elasticsearch.index.mapper.MappedFieldType;
import org.elasticsearch.index.query.BoolQueryBuilder;
@@ -20,6 +21,7 @@
import org.elasticsearch.index.query.QueryStringQueryBuilder;
import org.elasticsearch.index.query.RangeQueryBuilder;
+import java.util.List;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
@@ -56,15 +58,15 @@ public QueryBuilder toQueryBuilder(ParserRuleContext ctx) {
@Override
public QueryBuilder visitBooleanQuery(KqlBaseParser.BooleanQueryContext ctx) {
assert ctx.operator != null;
- return isAndQuery(ctx) ? visitAndBooleanQuery(ctx) : visitOrBooleanQuery(ctx);
+ return isAndQuery(ctx) ? visitAndBooleanQuery(ctx.query()) : visitOrBooleanQuery(ctx.query());
}
- public QueryBuilder visitAndBooleanQuery(KqlBaseParser.BooleanQueryContext ctx) {
+ public QueryBuilder visitAndBooleanQuery(List extends ParserRuleContext> clauses) {
BoolQueryBuilder builder = QueryBuilders.boolQuery();
// TODO: KQLContext has an option to wrap the clauses into a filter instead of a must clause. Do we need it?
- for (ParserRuleContext subQueryCtx : ctx.query()) {
- if (subQueryCtx instanceof KqlBaseParser.BooleanQueryContext booleanSubQueryCtx && isAndQuery(booleanSubQueryCtx)) {
+ for (ParserRuleContext subQueryCtx : clauses) {
+ if (isAndQuery(subQueryCtx)) {
typedParsing(this, subQueryCtx, BoolQueryBuilder.class).must().forEach(builder::must);
} else {
builder.must(typedParsing(this, subQueryCtx, QueryBuilder.class));
@@ -74,11 +76,11 @@ public QueryBuilder visitAndBooleanQuery(KqlBaseParser.BooleanQueryContext ctx)
return rewriteConjunctionQuery(builder);
}
- public QueryBuilder visitOrBooleanQuery(KqlBaseParser.BooleanQueryContext ctx) {
+ public QueryBuilder visitOrBooleanQuery(List extends ParserRuleContext> clauses) {
BoolQueryBuilder builder = QueryBuilders.boolQuery().minimumShouldMatch(1);
- for (ParserRuleContext subQueryCtx : ctx.query()) {
- if (subQueryCtx instanceof KqlBaseParser.BooleanQueryContext booleanSubQueryCtx && isOrQuery(booleanSubQueryCtx)) {
+ for (ParserRuleContext subQueryCtx : clauses) {
+ if (isOrQuery(subQueryCtx)) {
typedParsing(this, subQueryCtx, BoolQueryBuilder.class).should().forEach(builder::should);
} else {
builder.should(typedParsing(this, subQueryCtx, QueryBuilder.class));
@@ -100,8 +102,40 @@ public QueryBuilder visitParenthesizedQuery(KqlBaseParser.ParenthesizedQueryCont
@Override
public QueryBuilder visitNestedQuery(KqlBaseParser.NestedQueryContext ctx) {
- // TODO: implementation
- return new MatchNoneQueryBuilder();
+ String nestedFieldName = extractText(ctx.fieldName());
+
+ if (kqlParsingContext.isNestedField(nestedFieldName) == false) {
+ throw new KqlParsingException(
+ "[{}] is not a valid nested field name.",
+ ctx.start.getLine(),
+ ctx.start.getCharPositionInLine(),
+ nestedFieldName
+ );
+ }
+ QueryBuilder subQuery = kqlParsingContext.withNestedPath(
+ nestedFieldName,
+ () -> typedParsing(this, ctx.nestedSubQuery(), QueryBuilder.class)
+ );
+
+ if (subQuery instanceof MatchNoneQueryBuilder) {
+ return subQuery;
+ }
+
+ return wrapWithNestedQuery(
+ nestedFieldName,
+ QueryBuilders.nestedQuery(kqlParsingContext.fullFieldName(nestedFieldName), subQuery, ScoreMode.None)
+ );
+ }
+
+ @Override
+ public QueryBuilder visitBooleanNestedQuery(KqlBaseParser.BooleanNestedQueryContext ctx) {
+ assert ctx.operator != null;
+ return isAndQuery(ctx) ? visitAndBooleanQuery(ctx.nestedSubQuery()) : visitOrBooleanQuery(ctx.nestedSubQuery());
+ }
+
+ @Override
+ public QueryBuilder visitNestedParenthesizedQuery(KqlBaseParser.NestedParenthesizedQueryContext ctx) {
+ return typedParsing(this, ctx.nestedSubQuery(), QueryBuilder.class);
}
@Override
@@ -116,7 +150,7 @@ public QueryBuilder visitExistsQuery(KqlBaseParser.ExistsQueryContext ctx) {
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery().minimumShouldMatch(1);
withFields(ctx.fieldName(), (fieldName, mappedFieldType) -> {
if (isRuntimeField(mappedFieldType) == false) {
- boolQueryBuilder.should(QueryBuilders.existsQuery(fieldName));
+ boolQueryBuilder.should(wrapWithNestedQuery(fieldName, QueryBuilders.existsQuery(fieldName)));
}
});
@@ -137,7 +171,7 @@ public QueryBuilder visitRangeQuery(KqlBaseParser.RangeQueryContext ctx) {
rangeQuery.timeZone(kqlParsingContext.timeZone().getId());
}
- boolQueryBuilder.should(rangeQuery);
+ boolQueryBuilder.should(wrapWithNestedQuery(fieldName, rangeQuery));
});
return rewriteDisjunctionQuery(boolQueryBuilder);
@@ -200,24 +234,33 @@ public QueryBuilder visitFieldQuery(KqlBaseParser.FieldQueryContext ctx) {
}
if (fieldQuery != null) {
- boolQueryBuilder.should(fieldQuery);
+ boolQueryBuilder.should(wrapWithNestedQuery(fieldName, fieldQuery));
}
});
return rewriteDisjunctionQuery(boolQueryBuilder);
}
- private static boolean isAndQuery(KqlBaseParser.BooleanQueryContext ctx) {
- return ctx.operator.getType() == KqlBaseParser.AND;
+ private static boolean isAndQuery(ParserRuleContext ctx) {
+ return switch (ctx) {
+ case KqlBaseParser.BooleanQueryContext booleanQueryCtx -> booleanQueryCtx.operator.getType() == KqlBaseParser.AND;
+ case KqlBaseParser.BooleanNestedQueryContext booleanNestedCtx -> booleanNestedCtx.operator.getType() == KqlBaseParser.AND;
+ default -> false;
+ };
}
- private static boolean isOrQuery(KqlBaseParser.BooleanQueryContext ctx) {
- return ctx.operator.getType() == KqlBaseParser.OR;
+ private static boolean isOrQuery(ParserRuleContext ctx) {
+ return switch (ctx) {
+ case KqlBaseParser.BooleanQueryContext booleanQueryCtx -> booleanQueryCtx.operator.getType() == KqlBaseParser.OR;
+ case KqlBaseParser.BooleanNestedQueryContext booleanNestedCtx -> booleanNestedCtx.operator.getType() == KqlBaseParser.OR;
+ default -> false;
+ };
}
private void withFields(KqlBaseParser.FieldNameContext ctx, BiConsumer fieldConsummer) {
assert ctx != null : "Field ctx cannot be null";
String fieldNamePattern = extractText(ctx);
+
Set fieldNames = kqlParsingContext.resolveFieldNames(fieldNamePattern);
if (ctx.value.getType() == KqlBaseParser.QUOTED_STRING && Regex.isSimpleMatchPattern(fieldNamePattern)) {
@@ -267,4 +310,14 @@ private BiFunction rangeOperation(
default -> throw new IllegalArgumentException(format(null, "Invalid range operator {}\"", operator.getText()));
};
}
+
+ private QueryBuilder wrapWithNestedQuery(String fieldName, QueryBuilder query) {
+ String nestedPath = kqlParsingContext.nestedPath(fieldName);
+
+ if (nestedPath == null || nestedPath.equals(kqlParsingContext.currentNestedPath())) {
+ return query;
+ }
+
+ return wrapWithNestedQuery(nestedPath, QueryBuilders.nestedQuery(nestedPath, query, ScoreMode.None));
+ }
}
diff --git a/x-pack/plugin/kql/src/main/java/org/elasticsearch/xpack/kql/parser/KqlBase.interp b/x-pack/plugin/kql/src/main/java/org/elasticsearch/xpack/kql/parser/KqlBase.interp
index 7af37d7e3c3b..fbfe52afa4cd 100644
--- a/x-pack/plugin/kql/src/main/java/org/elasticsearch/xpack/kql/parser/KqlBase.interp
+++ b/x-pack/plugin/kql/src/main/java/org/elasticsearch/xpack/kql/parser/KqlBase.interp
@@ -42,6 +42,9 @@ query
simpleQuery
notQuery
nestedQuery
+nestedSubQuery
+nestedSimpleSubQuery
+nestedParenthesizedQuery
matchAllQuery
parenthesizedQuery
rangeQuery
@@ -54,4 +57,4 @@ fieldName
atn:
-[4, 1, 16, 136, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 1, 0, 3, 0, 30, 8, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 1, 40, 8, 1, 10, 1, 12, 1, 43, 9, 1, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 3, 2, 53, 8, 2, 1, 3, 1, 3, 1, 3, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 5, 1, 5, 3, 5, 66, 8, 5, 1, 5, 1, 5, 1, 6, 1, 6, 1, 6, 1, 6, 1, 7, 1, 7, 1, 7, 1, 7, 1, 8, 4, 8, 79, 8, 8, 11, 8, 12, 8, 80, 1, 8, 3, 8, 84, 8, 8, 1, 9, 1, 9, 1, 9, 1, 9, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 3, 10, 100, 8, 10, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 3, 11, 107, 8, 11, 1, 12, 3, 12, 110, 8, 12, 1, 12, 4, 12, 113, 8, 12, 11, 12, 12, 12, 114, 1, 12, 3, 12, 118, 8, 12, 1, 12, 1, 12, 3, 12, 122, 8, 12, 1, 12, 1, 12, 3, 12, 126, 8, 12, 1, 12, 3, 12, 129, 8, 12, 1, 13, 1, 13, 1, 13, 3, 13, 134, 8, 13, 1, 13, 0, 1, 2, 14, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 0, 4, 1, 0, 2, 3, 1, 0, 6, 9, 2, 0, 14, 14, 16, 16, 1, 0, 2, 4, 145, 0, 29, 1, 0, 0, 0, 2, 33, 1, 0, 0, 0, 4, 52, 1, 0, 0, 0, 6, 54, 1, 0, 0, 0, 8, 57, 1, 0, 0, 0, 10, 65, 1, 0, 0, 0, 12, 69, 1, 0, 0, 0, 14, 73, 1, 0, 0, 0, 16, 83, 1, 0, 0, 0, 18, 85, 1, 0, 0, 0, 20, 99, 1, 0, 0, 0, 22, 106, 1, 0, 0, 0, 24, 128, 1, 0, 0, 0, 26, 133, 1, 0, 0, 0, 28, 30, 3, 2, 1, 0, 29, 28, 1, 0, 0, 0, 29, 30, 1, 0, 0, 0, 30, 31, 1, 0, 0, 0, 31, 32, 5, 0, 0, 1, 32, 1, 1, 0, 0, 0, 33, 34, 6, 1, -1, 0, 34, 35, 3, 4, 2, 0, 35, 41, 1, 0, 0, 0, 36, 37, 10, 2, 0, 0, 37, 38, 7, 0, 0, 0, 38, 40, 3, 2, 1, 2, 39, 36, 1, 0, 0, 0, 40, 43, 1, 0, 0, 0, 41, 39, 1, 0, 0, 0, 41, 42, 1, 0, 0, 0, 42, 3, 1, 0, 0, 0, 43, 41, 1, 0, 0, 0, 44, 53, 3, 6, 3, 0, 45, 53, 3, 8, 4, 0, 46, 53, 3, 12, 6, 0, 47, 53, 3, 10, 5, 0, 48, 53, 3, 18, 9, 0, 49, 53, 3, 14, 7, 0, 50, 53, 3, 20, 10, 0, 51, 53, 3, 22, 11, 0, 52, 44, 1, 0, 0, 0, 52, 45, 1, 0, 0, 0, 52, 46, 1, 0, 0, 0, 52, 47, 1, 0, 0, 0, 52, 48, 1, 0, 0, 0, 52, 49, 1, 0, 0, 0, 52, 50, 1, 0, 0, 0, 52, 51, 1, 0, 0, 0, 53, 5, 1, 0, 0, 0, 54, 55, 5, 4, 0, 0, 55, 56, 3, 4, 2, 0, 56, 7, 1, 0, 0, 0, 57, 58, 3, 26, 13, 0, 58, 59, 5, 5, 0, 0, 59, 60, 5, 12, 0, 0, 60, 61, 3, 2, 1, 0, 61, 62, 5, 13, 0, 0, 62, 9, 1, 0, 0, 0, 63, 64, 5, 16, 0, 0, 64, 66, 5, 5, 0, 0, 65, 63, 1, 0, 0, 0, 65, 66, 1, 0, 0, 0, 66, 67, 1, 0, 0, 0, 67, 68, 5, 16, 0, 0, 68, 11, 1, 0, 0, 0, 69, 70, 5, 10, 0, 0, 70, 71, 3, 2, 1, 0, 71, 72, 5, 11, 0, 0, 72, 13, 1, 0, 0, 0, 73, 74, 3, 26, 13, 0, 74, 75, 7, 1, 0, 0, 75, 76, 3, 16, 8, 0, 76, 15, 1, 0, 0, 0, 77, 79, 7, 2, 0, 0, 78, 77, 1, 0, 0, 0, 79, 80, 1, 0, 0, 0, 80, 78, 1, 0, 0, 0, 80, 81, 1, 0, 0, 0, 81, 84, 1, 0, 0, 0, 82, 84, 5, 15, 0, 0, 83, 78, 1, 0, 0, 0, 83, 82, 1, 0, 0, 0, 84, 17, 1, 0, 0, 0, 85, 86, 3, 26, 13, 0, 86, 87, 5, 5, 0, 0, 87, 88, 5, 16, 0, 0, 88, 19, 1, 0, 0, 0, 89, 90, 3, 26, 13, 0, 90, 91, 5, 5, 0, 0, 91, 92, 3, 24, 12, 0, 92, 100, 1, 0, 0, 0, 93, 94, 3, 26, 13, 0, 94, 95, 5, 5, 0, 0, 95, 96, 5, 10, 0, 0, 96, 97, 3, 24, 12, 0, 97, 98, 5, 11, 0, 0, 98, 100, 1, 0, 0, 0, 99, 89, 1, 0, 0, 0, 99, 93, 1, 0, 0, 0, 100, 21, 1, 0, 0, 0, 101, 107, 3, 24, 12, 0, 102, 103, 5, 10, 0, 0, 103, 104, 3, 24, 12, 0, 104, 105, 5, 11, 0, 0, 105, 107, 1, 0, 0, 0, 106, 101, 1, 0, 0, 0, 106, 102, 1, 0, 0, 0, 107, 23, 1, 0, 0, 0, 108, 110, 7, 3, 0, 0, 109, 108, 1, 0, 0, 0, 109, 110, 1, 0, 0, 0, 110, 112, 1, 0, 0, 0, 111, 113, 7, 2, 0, 0, 112, 111, 1, 0, 0, 0, 113, 114, 1, 0, 0, 0, 114, 112, 1, 0, 0, 0, 114, 115, 1, 0, 0, 0, 115, 117, 1, 0, 0, 0, 116, 118, 7, 3, 0, 0, 117, 116, 1, 0, 0, 0, 117, 118, 1, 0, 0, 0, 118, 129, 1, 0, 0, 0, 119, 121, 7, 0, 0, 0, 120, 122, 7, 3, 0, 0, 121, 120, 1, 0, 0, 0, 121, 122, 1, 0, 0, 0, 122, 129, 1, 0, 0, 0, 123, 125, 5, 4, 0, 0, 124, 126, 7, 0, 0, 0, 125, 124, 1, 0, 0, 0, 125, 126, 1, 0, 0, 0, 126, 129, 1, 0, 0, 0, 127, 129, 5, 15, 0, 0, 128, 109, 1, 0, 0, 0, 128, 119, 1, 0, 0, 0, 128, 123, 1, 0, 0, 0, 128, 127, 1, 0, 0, 0, 129, 25, 1, 0, 0, 0, 130, 134, 5, 14, 0, 0, 131, 134, 5, 15, 0, 0, 132, 134, 5, 16, 0, 0, 133, 130, 1, 0, 0, 0, 133, 131, 1, 0, 0, 0, 133, 132, 1, 0, 0, 0, 134, 27, 1, 0, 0, 0, 15, 29, 41, 52, 65, 80, 83, 99, 106, 109, 114, 117, 121, 125, 128, 133]
\ No newline at end of file
+[4, 1, 16, 165, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 1, 0, 3, 0, 36, 8, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 1, 46, 8, 1, 10, 1, 12, 1, 49, 9, 1, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 3, 2, 59, 8, 2, 1, 3, 1, 3, 1, 3, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 5, 5, 76, 8, 5, 10, 5, 12, 5, 79, 9, 5, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 3, 6, 87, 8, 6, 1, 7, 1, 7, 1, 7, 1, 7, 1, 8, 1, 8, 3, 8, 95, 8, 8, 1, 8, 1, 8, 1, 9, 1, 9, 1, 9, 1, 9, 1, 10, 1, 10, 1, 10, 1, 10, 1, 11, 4, 11, 108, 8, 11, 11, 11, 12, 11, 109, 1, 11, 3, 11, 113, 8, 11, 1, 12, 1, 12, 1, 12, 1, 12, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 3, 13, 129, 8, 13, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 3, 14, 136, 8, 14, 1, 15, 3, 15, 139, 8, 15, 1, 15, 4, 15, 142, 8, 15, 11, 15, 12, 15, 143, 1, 15, 3, 15, 147, 8, 15, 1, 15, 1, 15, 3, 15, 151, 8, 15, 1, 15, 1, 15, 3, 15, 155, 8, 15, 1, 15, 3, 15, 158, 8, 15, 1, 16, 1, 16, 1, 16, 3, 16, 163, 8, 16, 1, 16, 0, 2, 2, 10, 17, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 0, 4, 1, 0, 2, 3, 1, 0, 6, 9, 2, 0, 14, 14, 16, 16, 1, 0, 2, 4, 177, 0, 35, 1, 0, 0, 0, 2, 39, 1, 0, 0, 0, 4, 58, 1, 0, 0, 0, 6, 60, 1, 0, 0, 0, 8, 63, 1, 0, 0, 0, 10, 69, 1, 0, 0, 0, 12, 86, 1, 0, 0, 0, 14, 88, 1, 0, 0, 0, 16, 94, 1, 0, 0, 0, 18, 98, 1, 0, 0, 0, 20, 102, 1, 0, 0, 0, 22, 112, 1, 0, 0, 0, 24, 114, 1, 0, 0, 0, 26, 128, 1, 0, 0, 0, 28, 135, 1, 0, 0, 0, 30, 157, 1, 0, 0, 0, 32, 162, 1, 0, 0, 0, 34, 36, 3, 2, 1, 0, 35, 34, 1, 0, 0, 0, 35, 36, 1, 0, 0, 0, 36, 37, 1, 0, 0, 0, 37, 38, 5, 0, 0, 1, 38, 1, 1, 0, 0, 0, 39, 40, 6, 1, -1, 0, 40, 41, 3, 4, 2, 0, 41, 47, 1, 0, 0, 0, 42, 43, 10, 2, 0, 0, 43, 44, 7, 0, 0, 0, 44, 46, 3, 2, 1, 2, 45, 42, 1, 0, 0, 0, 46, 49, 1, 0, 0, 0, 47, 45, 1, 0, 0, 0, 47, 48, 1, 0, 0, 0, 48, 3, 1, 0, 0, 0, 49, 47, 1, 0, 0, 0, 50, 59, 3, 6, 3, 0, 51, 59, 3, 8, 4, 0, 52, 59, 3, 18, 9, 0, 53, 59, 3, 16, 8, 0, 54, 59, 3, 24, 12, 0, 55, 59, 3, 20, 10, 0, 56, 59, 3, 26, 13, 0, 57, 59, 3, 28, 14, 0, 58, 50, 1, 0, 0, 0, 58, 51, 1, 0, 0, 0, 58, 52, 1, 0, 0, 0, 58, 53, 1, 0, 0, 0, 58, 54, 1, 0, 0, 0, 58, 55, 1, 0, 0, 0, 58, 56, 1, 0, 0, 0, 58, 57, 1, 0, 0, 0, 59, 5, 1, 0, 0, 0, 60, 61, 5, 4, 0, 0, 61, 62, 3, 4, 2, 0, 62, 7, 1, 0, 0, 0, 63, 64, 3, 32, 16, 0, 64, 65, 5, 5, 0, 0, 65, 66, 5, 12, 0, 0, 66, 67, 3, 10, 5, 0, 67, 68, 5, 13, 0, 0, 68, 9, 1, 0, 0, 0, 69, 70, 6, 5, -1, 0, 70, 71, 3, 12, 6, 0, 71, 77, 1, 0, 0, 0, 72, 73, 10, 2, 0, 0, 73, 74, 7, 0, 0, 0, 74, 76, 3, 10, 5, 2, 75, 72, 1, 0, 0, 0, 76, 79, 1, 0, 0, 0, 77, 75, 1, 0, 0, 0, 77, 78, 1, 0, 0, 0, 78, 11, 1, 0, 0, 0, 79, 77, 1, 0, 0, 0, 80, 87, 3, 6, 3, 0, 81, 87, 3, 8, 4, 0, 82, 87, 3, 14, 7, 0, 83, 87, 3, 24, 12, 0, 84, 87, 3, 20, 10, 0, 85, 87, 3, 26, 13, 0, 86, 80, 1, 0, 0, 0, 86, 81, 1, 0, 0, 0, 86, 82, 1, 0, 0, 0, 86, 83, 1, 0, 0, 0, 86, 84, 1, 0, 0, 0, 86, 85, 1, 0, 0, 0, 87, 13, 1, 0, 0, 0, 88, 89, 5, 10, 0, 0, 89, 90, 3, 10, 5, 0, 90, 91, 5, 11, 0, 0, 91, 15, 1, 0, 0, 0, 92, 93, 5, 16, 0, 0, 93, 95, 5, 5, 0, 0, 94, 92, 1, 0, 0, 0, 94, 95, 1, 0, 0, 0, 95, 96, 1, 0, 0, 0, 96, 97, 5, 16, 0, 0, 97, 17, 1, 0, 0, 0, 98, 99, 5, 10, 0, 0, 99, 100, 3, 2, 1, 0, 100, 101, 5, 11, 0, 0, 101, 19, 1, 0, 0, 0, 102, 103, 3, 32, 16, 0, 103, 104, 7, 1, 0, 0, 104, 105, 3, 22, 11, 0, 105, 21, 1, 0, 0, 0, 106, 108, 7, 2, 0, 0, 107, 106, 1, 0, 0, 0, 108, 109, 1, 0, 0, 0, 109, 107, 1, 0, 0, 0, 109, 110, 1, 0, 0, 0, 110, 113, 1, 0, 0, 0, 111, 113, 5, 15, 0, 0, 112, 107, 1, 0, 0, 0, 112, 111, 1, 0, 0, 0, 113, 23, 1, 0, 0, 0, 114, 115, 3, 32, 16, 0, 115, 116, 5, 5, 0, 0, 116, 117, 5, 16, 0, 0, 117, 25, 1, 0, 0, 0, 118, 119, 3, 32, 16, 0, 119, 120, 5, 5, 0, 0, 120, 121, 3, 30, 15, 0, 121, 129, 1, 0, 0, 0, 122, 123, 3, 32, 16, 0, 123, 124, 5, 5, 0, 0, 124, 125, 5, 10, 0, 0, 125, 126, 3, 30, 15, 0, 126, 127, 5, 11, 0, 0, 127, 129, 1, 0, 0, 0, 128, 118, 1, 0, 0, 0, 128, 122, 1, 0, 0, 0, 129, 27, 1, 0, 0, 0, 130, 136, 3, 30, 15, 0, 131, 132, 5, 10, 0, 0, 132, 133, 3, 30, 15, 0, 133, 134, 5, 11, 0, 0, 134, 136, 1, 0, 0, 0, 135, 130, 1, 0, 0, 0, 135, 131, 1, 0, 0, 0, 136, 29, 1, 0, 0, 0, 137, 139, 7, 3, 0, 0, 138, 137, 1, 0, 0, 0, 138, 139, 1, 0, 0, 0, 139, 141, 1, 0, 0, 0, 140, 142, 7, 2, 0, 0, 141, 140, 1, 0, 0, 0, 142, 143, 1, 0, 0, 0, 143, 141, 1, 0, 0, 0, 143, 144, 1, 0, 0, 0, 144, 146, 1, 0, 0, 0, 145, 147, 7, 3, 0, 0, 146, 145, 1, 0, 0, 0, 146, 147, 1, 0, 0, 0, 147, 158, 1, 0, 0, 0, 148, 150, 7, 0, 0, 0, 149, 151, 7, 3, 0, 0, 150, 149, 1, 0, 0, 0, 150, 151, 1, 0, 0, 0, 151, 158, 1, 0, 0, 0, 152, 154, 5, 4, 0, 0, 153, 155, 7, 0, 0, 0, 154, 153, 1, 0, 0, 0, 154, 155, 1, 0, 0, 0, 155, 158, 1, 0, 0, 0, 156, 158, 5, 15, 0, 0, 157, 138, 1, 0, 0, 0, 157, 148, 1, 0, 0, 0, 157, 152, 1, 0, 0, 0, 157, 156, 1, 0, 0, 0, 158, 31, 1, 0, 0, 0, 159, 163, 5, 14, 0, 0, 160, 163, 5, 15, 0, 0, 161, 163, 5, 16, 0, 0, 162, 159, 1, 0, 0, 0, 162, 160, 1, 0, 0, 0, 162, 161, 1, 0, 0, 0, 163, 33, 1, 0, 0, 0, 17, 35, 47, 58, 77, 86, 94, 109, 112, 128, 135, 138, 143, 146, 150, 154, 157, 162]
\ No newline at end of file
diff --git a/x-pack/plugin/kql/src/main/java/org/elasticsearch/xpack/kql/parser/KqlBaseBaseListener.java b/x-pack/plugin/kql/src/main/java/org/elasticsearch/xpack/kql/parser/KqlBaseBaseListener.java
index e1015edcd493..c3fc1281b6fd 100644
--- a/x-pack/plugin/kql/src/main/java/org/elasticsearch/xpack/kql/parser/KqlBaseBaseListener.java
+++ b/x-pack/plugin/kql/src/main/java/org/elasticsearch/xpack/kql/parser/KqlBaseBaseListener.java
@@ -92,6 +92,54 @@ class KqlBaseBaseListener implements KqlBaseListener {
* The default implementation does nothing.
*/
@Override public void exitNestedQuery(KqlBaseParser.NestedQueryContext ctx) { }
+ /**
+ * {@inheritDoc}
+ *
+ * The default implementation does nothing.
+ */
+ @Override public void enterBooleanNestedQuery(KqlBaseParser.BooleanNestedQueryContext ctx) { }
+ /**
+ * {@inheritDoc}
+ *
+ * The default implementation does nothing.
+ */
+ @Override public void exitBooleanNestedQuery(KqlBaseParser.BooleanNestedQueryContext ctx) { }
+ /**
+ * {@inheritDoc}
+ *
+ * The default implementation does nothing.
+ */
+ @Override public void enterDefaultNestedQuery(KqlBaseParser.DefaultNestedQueryContext ctx) { }
+ /**
+ * {@inheritDoc}
+ *
+ * The default implementation does nothing.
+ */
+ @Override public void exitDefaultNestedQuery(KqlBaseParser.DefaultNestedQueryContext ctx) { }
+ /**
+ * {@inheritDoc}
+ *
+ * The default implementation does nothing.
+ */
+ @Override public void enterNestedSimpleSubQuery(KqlBaseParser.NestedSimpleSubQueryContext ctx) { }
+ /**
+ * {@inheritDoc}
+ *
+ * The default implementation does nothing.
+ */
+ @Override public void exitNestedSimpleSubQuery(KqlBaseParser.NestedSimpleSubQueryContext ctx) { }
+ /**
+ * {@inheritDoc}
+ *
+ * The default implementation does nothing.
+ */
+ @Override public void enterNestedParenthesizedQuery(KqlBaseParser.NestedParenthesizedQueryContext ctx) { }
+ /**
+ * {@inheritDoc}
+ *
+ * The default implementation does nothing.
+ */
+ @Override public void exitNestedParenthesizedQuery(KqlBaseParser.NestedParenthesizedQueryContext ctx) { }
/**
* {@inheritDoc}
*
diff --git a/x-pack/plugin/kql/src/main/java/org/elasticsearch/xpack/kql/parser/KqlBaseBaseVisitor.java b/x-pack/plugin/kql/src/main/java/org/elasticsearch/xpack/kql/parser/KqlBaseBaseVisitor.java
index 3973a647c8cd..84c882c2e2bc 100644
--- a/x-pack/plugin/kql/src/main/java/org/elasticsearch/xpack/kql/parser/KqlBaseBaseVisitor.java
+++ b/x-pack/plugin/kql/src/main/java/org/elasticsearch/xpack/kql/parser/KqlBaseBaseVisitor.java
@@ -62,6 +62,34 @@ class KqlBaseBaseVisitor extends AbstractParseTreeVisitor implements KqlBa
* {@link #visitChildren} on {@code ctx}.
*/
@Override public T visitNestedQuery(KqlBaseParser.NestedQueryContext ctx) { return visitChildren(ctx); }
+ /**
+ * {@inheritDoc}
+ *
+ * The default implementation returns the result of calling
+ * {@link #visitChildren} on {@code ctx}.
+ */
+ @Override public T visitBooleanNestedQuery(KqlBaseParser.BooleanNestedQueryContext ctx) { return visitChildren(ctx); }
+ /**
+ * {@inheritDoc}
+ *
+ * The default implementation returns the result of calling
+ * {@link #visitChildren} on {@code ctx}.
+ */
+ @Override public T visitDefaultNestedQuery(KqlBaseParser.DefaultNestedQueryContext ctx) { return visitChildren(ctx); }
+ /**
+ * {@inheritDoc}
+ *
+ * The default implementation returns the result of calling
+ * {@link #visitChildren} on {@code ctx}.
+ */
+ @Override public T visitNestedSimpleSubQuery(KqlBaseParser.NestedSimpleSubQueryContext ctx) { return visitChildren(ctx); }
+ /**
+ * {@inheritDoc}
+ *
+ * The default implementation returns the result of calling
+ * {@link #visitChildren} on {@code ctx}.
+ */
+ @Override public T visitNestedParenthesizedQuery(KqlBaseParser.NestedParenthesizedQueryContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
diff --git a/x-pack/plugin/kql/src/main/java/org/elasticsearch/xpack/kql/parser/KqlBaseListener.java b/x-pack/plugin/kql/src/main/java/org/elasticsearch/xpack/kql/parser/KqlBaseListener.java
index 49f203120864..a44ecf1ecad2 100644
--- a/x-pack/plugin/kql/src/main/java/org/elasticsearch/xpack/kql/parser/KqlBaseListener.java
+++ b/x-pack/plugin/kql/src/main/java/org/elasticsearch/xpack/kql/parser/KqlBaseListener.java
@@ -79,6 +79,50 @@ interface KqlBaseListener extends ParseTreeListener {
* @param ctx the parse tree
*/
void exitNestedQuery(KqlBaseParser.NestedQueryContext ctx);
+ /**
+ * Enter a parse tree produced by the {@code booleanNestedQuery}
+ * labeled alternative in {@link KqlBaseParser#nestedSubQuery}.
+ * @param ctx the parse tree
+ */
+ void enterBooleanNestedQuery(KqlBaseParser.BooleanNestedQueryContext ctx);
+ /**
+ * Exit a parse tree produced by the {@code booleanNestedQuery}
+ * labeled alternative in {@link KqlBaseParser#nestedSubQuery}.
+ * @param ctx the parse tree
+ */
+ void exitBooleanNestedQuery(KqlBaseParser.BooleanNestedQueryContext ctx);
+ /**
+ * Enter a parse tree produced by the {@code defaultNestedQuery}
+ * labeled alternative in {@link KqlBaseParser#nestedSubQuery}.
+ * @param ctx the parse tree
+ */
+ void enterDefaultNestedQuery(KqlBaseParser.DefaultNestedQueryContext ctx);
+ /**
+ * Exit a parse tree produced by the {@code defaultNestedQuery}
+ * labeled alternative in {@link KqlBaseParser#nestedSubQuery}.
+ * @param ctx the parse tree
+ */
+ void exitDefaultNestedQuery(KqlBaseParser.DefaultNestedQueryContext ctx);
+ /**
+ * Enter a parse tree produced by {@link KqlBaseParser#nestedSimpleSubQuery}.
+ * @param ctx the parse tree
+ */
+ void enterNestedSimpleSubQuery(KqlBaseParser.NestedSimpleSubQueryContext ctx);
+ /**
+ * Exit a parse tree produced by {@link KqlBaseParser#nestedSimpleSubQuery}.
+ * @param ctx the parse tree
+ */
+ void exitNestedSimpleSubQuery(KqlBaseParser.NestedSimpleSubQueryContext ctx);
+ /**
+ * Enter a parse tree produced by {@link KqlBaseParser#nestedParenthesizedQuery}.
+ * @param ctx the parse tree
+ */
+ void enterNestedParenthesizedQuery(KqlBaseParser.NestedParenthesizedQueryContext ctx);
+ /**
+ * Exit a parse tree produced by {@link KqlBaseParser#nestedParenthesizedQuery}.
+ * @param ctx the parse tree
+ */
+ void exitNestedParenthesizedQuery(KqlBaseParser.NestedParenthesizedQueryContext ctx);
/**
* Enter a parse tree produced by {@link KqlBaseParser#matchAllQuery}.
* @param ctx the parse tree
diff --git a/x-pack/plugin/kql/src/main/java/org/elasticsearch/xpack/kql/parser/KqlBaseParser.java b/x-pack/plugin/kql/src/main/java/org/elasticsearch/xpack/kql/parser/KqlBaseParser.java
index 118ac32aadd6..7e797b9edbb9 100644
--- a/x-pack/plugin/kql/src/main/java/org/elasticsearch/xpack/kql/parser/KqlBaseParser.java
+++ b/x-pack/plugin/kql/src/main/java/org/elasticsearch/xpack/kql/parser/KqlBaseParser.java
@@ -30,12 +30,15 @@ class KqlBaseParser extends Parser {
RIGHT_CURLY_BRACKET=13, UNQUOTED_LITERAL=14, QUOTED_STRING=15, WILDCARD=16;
public static final int
RULE_topLevelQuery = 0, RULE_query = 1, RULE_simpleQuery = 2, RULE_notQuery = 3,
- RULE_nestedQuery = 4, RULE_matchAllQuery = 5, RULE_parenthesizedQuery = 6,
- RULE_rangeQuery = 7, RULE_rangeQueryValue = 8, RULE_existsQuery = 9, RULE_fieldQuery = 10,
- RULE_fieldLessQuery = 11, RULE_fieldQueryValue = 12, RULE_fieldName = 13;
+ RULE_nestedQuery = 4, RULE_nestedSubQuery = 5, RULE_nestedSimpleSubQuery = 6,
+ RULE_nestedParenthesizedQuery = 7, RULE_matchAllQuery = 8, RULE_parenthesizedQuery = 9,
+ RULE_rangeQuery = 10, RULE_rangeQueryValue = 11, RULE_existsQuery = 12,
+ RULE_fieldQuery = 13, RULE_fieldLessQuery = 14, RULE_fieldQueryValue = 15,
+ RULE_fieldName = 16;
private static String[] makeRuleNames() {
return new String[] {
- "topLevelQuery", "query", "simpleQuery", "notQuery", "nestedQuery", "matchAllQuery",
+ "topLevelQuery", "query", "simpleQuery", "notQuery", "nestedQuery", "nestedSubQuery",
+ "nestedSimpleSubQuery", "nestedParenthesizedQuery", "matchAllQuery",
"parenthesizedQuery", "rangeQuery", "rangeQueryValue", "existsQuery",
"fieldQuery", "fieldLessQuery", "fieldQueryValue", "fieldName"
};
@@ -139,17 +142,17 @@ public final TopLevelQueryContext topLevelQuery() throws RecognitionException {
try {
enterOuterAlt(_localctx, 1);
{
- setState(29);
+ setState(35);
_errHandler.sync(this);
_la = _input.LA(1);
if ((((_la) & ~0x3f) == 0 && ((1L << _la) & 115740L) != 0)) {
{
- setState(28);
+ setState(34);
query(0);
}
}
- setState(31);
+ setState(37);
match(EOF);
}
}
@@ -244,11 +247,11 @@ private QueryContext query(int _p) throws RecognitionException {
_ctx = _localctx;
_prevctx = _localctx;
- setState(34);
+ setState(40);
simpleQuery();
}
_ctx.stop = _input.LT(-1);
- setState(41);
+ setState(47);
_errHandler.sync(this);
_alt = getInterpreter().adaptivePredict(_input,1,_ctx);
while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) {
@@ -259,9 +262,9 @@ private QueryContext query(int _p) throws RecognitionException {
{
_localctx = new BooleanQueryContext(new QueryContext(_parentctx, _parentState));
pushNewRecursionContext(_localctx, _startState, RULE_query);
- setState(36);
+ setState(42);
if (!(precpred(_ctx, 2))) throw new FailedPredicateException(this, "precpred(_ctx, 2)");
- setState(37);
+ setState(43);
((BooleanQueryContext)_localctx).operator = _input.LT(1);
_la = _input.LA(1);
if ( !(_la==AND || _la==OR) ) {
@@ -272,12 +275,12 @@ private QueryContext query(int _p) throws RecognitionException {
_errHandler.reportMatch(this);
consume();
}
- setState(38);
+ setState(44);
query(2);
}
}
}
- setState(43);
+ setState(49);
_errHandler.sync(this);
_alt = getInterpreter().adaptivePredict(_input,1,_ctx);
}
@@ -343,62 +346,62 @@ public final SimpleQueryContext simpleQuery() throws RecognitionException {
SimpleQueryContext _localctx = new SimpleQueryContext(_ctx, getState());
enterRule(_localctx, 4, RULE_simpleQuery);
try {
- setState(52);
+ setState(58);
_errHandler.sync(this);
switch ( getInterpreter().adaptivePredict(_input,2,_ctx) ) {
case 1:
enterOuterAlt(_localctx, 1);
{
- setState(44);
+ setState(50);
notQuery();
}
break;
case 2:
enterOuterAlt(_localctx, 2);
{
- setState(45);
+ setState(51);
nestedQuery();
}
break;
case 3:
enterOuterAlt(_localctx, 3);
{
- setState(46);
+ setState(52);
parenthesizedQuery();
}
break;
case 4:
enterOuterAlt(_localctx, 4);
{
- setState(47);
+ setState(53);
matchAllQuery();
}
break;
case 5:
enterOuterAlt(_localctx, 5);
{
- setState(48);
+ setState(54);
existsQuery();
}
break;
case 6:
enterOuterAlt(_localctx, 6);
{
- setState(49);
+ setState(55);
rangeQuery();
}
break;
case 7:
enterOuterAlt(_localctx, 7);
{
- setState(50);
+ setState(56);
fieldQuery();
}
break;
case 8:
enterOuterAlt(_localctx, 8);
{
- setState(51);
+ setState(57);
fieldLessQuery();
}
break;
@@ -447,9 +450,9 @@ public final NotQueryContext notQuery() throws RecognitionException {
try {
enterOuterAlt(_localctx, 1);
{
- setState(54);
+ setState(60);
match(NOT);
- setState(55);
+ setState(61);
((NotQueryContext)_localctx).subQuery = simpleQuery();
}
}
@@ -471,8 +474,8 @@ public FieldNameContext fieldName() {
}
public TerminalNode COLON() { return getToken(KqlBaseParser.COLON, 0); }
public TerminalNode LEFT_CURLY_BRACKET() { return getToken(KqlBaseParser.LEFT_CURLY_BRACKET, 0); }
- public QueryContext query() {
- return getRuleContext(QueryContext.class,0);
+ public NestedSubQueryContext nestedSubQuery() {
+ return getRuleContext(NestedSubQueryContext.class,0);
}
public TerminalNode RIGHT_CURLY_BRACKET() { return getToken(KqlBaseParser.RIGHT_CURLY_BRACKET, 0); }
public NestedQueryContext(ParserRuleContext parent, int invokingState) {
@@ -500,15 +503,15 @@ public final NestedQueryContext nestedQuery() throws RecognitionException {
try {
enterOuterAlt(_localctx, 1);
{
- setState(57);
+ setState(63);
fieldName();
- setState(58);
+ setState(64);
match(COLON);
- setState(59);
+ setState(65);
match(LEFT_CURLY_BRACKET);
- setState(60);
- query(0);
- setState(61);
+ setState(66);
+ nestedSubQuery(0);
+ setState(67);
match(RIGHT_CURLY_BRACKET);
}
}
@@ -523,6 +526,288 @@ public final NestedQueryContext nestedQuery() throws RecognitionException {
return _localctx;
}
+ @SuppressWarnings("CheckReturnValue")
+ public static class NestedSubQueryContext extends ParserRuleContext {
+ public NestedSubQueryContext(ParserRuleContext parent, int invokingState) {
+ super(parent, invokingState);
+ }
+ @Override public int getRuleIndex() { return RULE_nestedSubQuery; }
+
+ public NestedSubQueryContext() { }
+ public void copyFrom(NestedSubQueryContext ctx) {
+ super.copyFrom(ctx);
+ }
+ }
+ @SuppressWarnings("CheckReturnValue")
+ public static class BooleanNestedQueryContext extends NestedSubQueryContext {
+ public Token operator;
+ public List nestedSubQuery() {
+ return getRuleContexts(NestedSubQueryContext.class);
+ }
+ public NestedSubQueryContext nestedSubQuery(int i) {
+ return getRuleContext(NestedSubQueryContext.class,i);
+ }
+ public TerminalNode AND() { return getToken(KqlBaseParser.AND, 0); }
+ public TerminalNode OR() { return getToken(KqlBaseParser.OR, 0); }
+ public BooleanNestedQueryContext(NestedSubQueryContext ctx) { copyFrom(ctx); }
+ @Override
+ public void enterRule(ParseTreeListener listener) {
+ if ( listener instanceof KqlBaseListener ) ((KqlBaseListener)listener).enterBooleanNestedQuery(this);
+ }
+ @Override
+ public void exitRule(ParseTreeListener listener) {
+ if ( listener instanceof KqlBaseListener ) ((KqlBaseListener)listener).exitBooleanNestedQuery(this);
+ }
+ @Override
+ public T accept(ParseTreeVisitor extends T> visitor) {
+ if ( visitor instanceof KqlBaseVisitor ) return ((KqlBaseVisitor extends T>)visitor).visitBooleanNestedQuery(this);
+ else return visitor.visitChildren(this);
+ }
+ }
+ @SuppressWarnings("CheckReturnValue")
+ public static class DefaultNestedQueryContext extends NestedSubQueryContext {
+ public NestedSimpleSubQueryContext nestedSimpleSubQuery() {
+ return getRuleContext(NestedSimpleSubQueryContext.class,0);
+ }
+ public DefaultNestedQueryContext(NestedSubQueryContext ctx) { copyFrom(ctx); }
+ @Override
+ public void enterRule(ParseTreeListener listener) {
+ if ( listener instanceof KqlBaseListener ) ((KqlBaseListener)listener).enterDefaultNestedQuery(this);
+ }
+ @Override
+ public void exitRule(ParseTreeListener listener) {
+ if ( listener instanceof KqlBaseListener ) ((KqlBaseListener)listener).exitDefaultNestedQuery(this);
+ }
+ @Override
+ public T accept(ParseTreeVisitor extends T> visitor) {
+ if ( visitor instanceof KqlBaseVisitor ) return ((KqlBaseVisitor extends T>)visitor).visitDefaultNestedQuery(this);
+ else return visitor.visitChildren(this);
+ }
+ }
+
+ public final NestedSubQueryContext nestedSubQuery() throws RecognitionException {
+ return nestedSubQuery(0);
+ }
+
+ private NestedSubQueryContext nestedSubQuery(int _p) throws RecognitionException {
+ ParserRuleContext _parentctx = _ctx;
+ int _parentState = getState();
+ NestedSubQueryContext _localctx = new NestedSubQueryContext(_ctx, _parentState);
+ NestedSubQueryContext _prevctx = _localctx;
+ int _startState = 10;
+ enterRecursionRule(_localctx, 10, RULE_nestedSubQuery, _p);
+ int _la;
+ try {
+ int _alt;
+ enterOuterAlt(_localctx, 1);
+ {
+ {
+ _localctx = new DefaultNestedQueryContext(_localctx);
+ _ctx = _localctx;
+ _prevctx = _localctx;
+
+ setState(70);
+ nestedSimpleSubQuery();
+ }
+ _ctx.stop = _input.LT(-1);
+ setState(77);
+ _errHandler.sync(this);
+ _alt = getInterpreter().adaptivePredict(_input,3,_ctx);
+ while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) {
+ if ( _alt==1 ) {
+ if ( _parseListeners!=null ) triggerExitRuleEvent();
+ _prevctx = _localctx;
+ {
+ {
+ _localctx = new BooleanNestedQueryContext(new NestedSubQueryContext(_parentctx, _parentState));
+ pushNewRecursionContext(_localctx, _startState, RULE_nestedSubQuery);
+ setState(72);
+ if (!(precpred(_ctx, 2))) throw new FailedPredicateException(this, "precpred(_ctx, 2)");
+ setState(73);
+ ((BooleanNestedQueryContext)_localctx).operator = _input.LT(1);
+ _la = _input.LA(1);
+ if ( !(_la==AND || _la==OR) ) {
+ ((BooleanNestedQueryContext)_localctx).operator = (Token)_errHandler.recoverInline(this);
+ }
+ else {
+ if ( _input.LA(1)==Token.EOF ) matchedEOF = true;
+ _errHandler.reportMatch(this);
+ consume();
+ }
+ setState(74);
+ nestedSubQuery(2);
+ }
+ }
+ }
+ setState(79);
+ _errHandler.sync(this);
+ _alt = getInterpreter().adaptivePredict(_input,3,_ctx);
+ }
+ }
+ }
+ catch (RecognitionException re) {
+ _localctx.exception = re;
+ _errHandler.reportError(this, re);
+ _errHandler.recover(this, re);
+ }
+ finally {
+ unrollRecursionContexts(_parentctx);
+ }
+ return _localctx;
+ }
+
+ @SuppressWarnings("CheckReturnValue")
+ public static class NestedSimpleSubQueryContext extends ParserRuleContext {
+ public NotQueryContext notQuery() {
+ return getRuleContext(NotQueryContext.class,0);
+ }
+ public NestedQueryContext nestedQuery() {
+ return getRuleContext(NestedQueryContext.class,0);
+ }
+ public NestedParenthesizedQueryContext nestedParenthesizedQuery() {
+ return getRuleContext(NestedParenthesizedQueryContext.class,0);
+ }
+ public ExistsQueryContext existsQuery() {
+ return getRuleContext(ExistsQueryContext.class,0);
+ }
+ public RangeQueryContext rangeQuery() {
+ return getRuleContext(RangeQueryContext.class,0);
+ }
+ public FieldQueryContext fieldQuery() {
+ return getRuleContext(FieldQueryContext.class,0);
+ }
+ public NestedSimpleSubQueryContext(ParserRuleContext parent, int invokingState) {
+ super(parent, invokingState);
+ }
+ @Override public int getRuleIndex() { return RULE_nestedSimpleSubQuery; }
+ @Override
+ public void enterRule(ParseTreeListener listener) {
+ if ( listener instanceof KqlBaseListener ) ((KqlBaseListener)listener).enterNestedSimpleSubQuery(this);
+ }
+ @Override
+ public void exitRule(ParseTreeListener listener) {
+ if ( listener instanceof KqlBaseListener ) ((KqlBaseListener)listener).exitNestedSimpleSubQuery(this);
+ }
+ @Override
+ public T accept(ParseTreeVisitor extends T> visitor) {
+ if ( visitor instanceof KqlBaseVisitor ) return ((KqlBaseVisitor extends T>)visitor).visitNestedSimpleSubQuery(this);
+ else return visitor.visitChildren(this);
+ }
+ }
+
+ public final NestedSimpleSubQueryContext nestedSimpleSubQuery() throws RecognitionException {
+ NestedSimpleSubQueryContext _localctx = new NestedSimpleSubQueryContext(_ctx, getState());
+ enterRule(_localctx, 12, RULE_nestedSimpleSubQuery);
+ try {
+ setState(86);
+ _errHandler.sync(this);
+ switch ( getInterpreter().adaptivePredict(_input,4,_ctx) ) {
+ case 1:
+ enterOuterAlt(_localctx, 1);
+ {
+ setState(80);
+ notQuery();
+ }
+ break;
+ case 2:
+ enterOuterAlt(_localctx, 2);
+ {
+ setState(81);
+ nestedQuery();
+ }
+ break;
+ case 3:
+ enterOuterAlt(_localctx, 3);
+ {
+ setState(82);
+ nestedParenthesizedQuery();
+ }
+ break;
+ case 4:
+ enterOuterAlt(_localctx, 4);
+ {
+ setState(83);
+ existsQuery();
+ }
+ break;
+ case 5:
+ enterOuterAlt(_localctx, 5);
+ {
+ setState(84);
+ rangeQuery();
+ }
+ break;
+ case 6:
+ enterOuterAlt(_localctx, 6);
+ {
+ setState(85);
+ fieldQuery();
+ }
+ break;
+ }
+ }
+ catch (RecognitionException re) {
+ _localctx.exception = re;
+ _errHandler.reportError(this, re);
+ _errHandler.recover(this, re);
+ }
+ finally {
+ exitRule();
+ }
+ return _localctx;
+ }
+
+ @SuppressWarnings("CheckReturnValue")
+ public static class NestedParenthesizedQueryContext extends ParserRuleContext {
+ public TerminalNode LEFT_PARENTHESIS() { return getToken(KqlBaseParser.LEFT_PARENTHESIS, 0); }
+ public NestedSubQueryContext nestedSubQuery() {
+ return getRuleContext(NestedSubQueryContext.class,0);
+ }
+ public TerminalNode RIGHT_PARENTHESIS() { return getToken(KqlBaseParser.RIGHT_PARENTHESIS, 0); }
+ public NestedParenthesizedQueryContext(ParserRuleContext parent, int invokingState) {
+ super(parent, invokingState);
+ }
+ @Override public int getRuleIndex() { return RULE_nestedParenthesizedQuery; }
+ @Override
+ public void enterRule(ParseTreeListener listener) {
+ if ( listener instanceof KqlBaseListener ) ((KqlBaseListener)listener).enterNestedParenthesizedQuery(this);
+ }
+ @Override
+ public void exitRule(ParseTreeListener listener) {
+ if ( listener instanceof KqlBaseListener ) ((KqlBaseListener)listener).exitNestedParenthesizedQuery(this);
+ }
+ @Override
+ public T accept(ParseTreeVisitor extends T> visitor) {
+ if ( visitor instanceof KqlBaseVisitor ) return ((KqlBaseVisitor extends T>)visitor).visitNestedParenthesizedQuery(this);
+ else return visitor.visitChildren(this);
+ }
+ }
+
+ public final NestedParenthesizedQueryContext nestedParenthesizedQuery() throws RecognitionException {
+ NestedParenthesizedQueryContext _localctx = new NestedParenthesizedQueryContext(_ctx, getState());
+ enterRule(_localctx, 14, RULE_nestedParenthesizedQuery);
+ try {
+ enterOuterAlt(_localctx, 1);
+ {
+ setState(88);
+ match(LEFT_PARENTHESIS);
+ setState(89);
+ nestedSubQuery(0);
+ setState(90);
+ match(RIGHT_PARENTHESIS);
+ }
+ }
+ catch (RecognitionException re) {
+ _localctx.exception = re;
+ _errHandler.reportError(this, re);
+ _errHandler.recover(this, re);
+ }
+ finally {
+ exitRule();
+ }
+ return _localctx;
+ }
+
@SuppressWarnings("CheckReturnValue")
public static class MatchAllQueryContext extends ParserRuleContext {
public List WILDCARD() { return getTokens(KqlBaseParser.WILDCARD); }
@@ -551,23 +836,23 @@ public T accept(ParseTreeVisitor extends T> visitor) {
public final MatchAllQueryContext matchAllQuery() throws RecognitionException {
MatchAllQueryContext _localctx = new MatchAllQueryContext(_ctx, getState());
- enterRule(_localctx, 10, RULE_matchAllQuery);
+ enterRule(_localctx, 16, RULE_matchAllQuery);
try {
enterOuterAlt(_localctx, 1);
{
- setState(65);
+ setState(94);
_errHandler.sync(this);
- switch ( getInterpreter().adaptivePredict(_input,3,_ctx) ) {
+ switch ( getInterpreter().adaptivePredict(_input,5,_ctx) ) {
case 1:
{
- setState(63);
+ setState(92);
match(WILDCARD);
- setState(64);
+ setState(93);
match(COLON);
}
break;
}
- setState(67);
+ setState(96);
match(WILDCARD);
}
}
@@ -610,15 +895,15 @@ public T accept(ParseTreeVisitor extends T> visitor) {
public final ParenthesizedQueryContext parenthesizedQuery() throws RecognitionException {
ParenthesizedQueryContext _localctx = new ParenthesizedQueryContext(_ctx, getState());
- enterRule(_localctx, 12, RULE_parenthesizedQuery);
+ enterRule(_localctx, 18, RULE_parenthesizedQuery);
try {
enterOuterAlt(_localctx, 1);
{
- setState(69);
+ setState(98);
match(LEFT_PARENTHESIS);
- setState(70);
+ setState(99);
query(0);
- setState(71);
+ setState(100);
match(RIGHT_PARENTHESIS);
}
}
@@ -667,14 +952,14 @@ public T accept(ParseTreeVisitor extends T> visitor) {
public final RangeQueryContext rangeQuery() throws RecognitionException {
RangeQueryContext _localctx = new RangeQueryContext(_ctx, getState());
- enterRule(_localctx, 14, RULE_rangeQuery);
+ enterRule(_localctx, 20, RULE_rangeQuery);
int _la;
try {
enterOuterAlt(_localctx, 1);
{
- setState(73);
+ setState(102);
fieldName();
- setState(74);
+ setState(103);
((RangeQueryContext)_localctx).operator = _input.LT(1);
_la = _input.LA(1);
if ( !((((_la) & ~0x3f) == 0 && ((1L << _la) & 960L) != 0)) ) {
@@ -685,7 +970,7 @@ public final RangeQueryContext rangeQuery() throws RecognitionException {
_errHandler.reportMatch(this);
consume();
}
- setState(75);
+ setState(104);
rangeQueryValue();
}
}
@@ -732,18 +1017,18 @@ public T accept(ParseTreeVisitor extends T> visitor) {
public final RangeQueryValueContext rangeQueryValue() throws RecognitionException {
RangeQueryValueContext _localctx = new RangeQueryValueContext(_ctx, getState());
- enterRule(_localctx, 16, RULE_rangeQueryValue);
+ enterRule(_localctx, 22, RULE_rangeQueryValue);
int _la;
try {
int _alt;
- setState(83);
+ setState(112);
_errHandler.sync(this);
switch (_input.LA(1)) {
case UNQUOTED_LITERAL:
case WILDCARD:
enterOuterAlt(_localctx, 1);
{
- setState(78);
+ setState(107);
_errHandler.sync(this);
_alt = 1;
do {
@@ -751,7 +1036,7 @@ public final RangeQueryValueContext rangeQueryValue() throws RecognitionExceptio
case 1:
{
{
- setState(77);
+ setState(106);
_la = _input.LA(1);
if ( !(_la==UNQUOTED_LITERAL || _la==WILDCARD) ) {
_errHandler.recoverInline(this);
@@ -767,16 +1052,16 @@ public final RangeQueryValueContext rangeQueryValue() throws RecognitionExceptio
default:
throw new NoViableAltException(this);
}
- setState(80);
+ setState(109);
_errHandler.sync(this);
- _alt = getInterpreter().adaptivePredict(_input,4,_ctx);
+ _alt = getInterpreter().adaptivePredict(_input,6,_ctx);
} while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER );
}
break;
case QUOTED_STRING:
enterOuterAlt(_localctx, 2);
{
- setState(82);
+ setState(111);
match(QUOTED_STRING);
}
break;
@@ -823,15 +1108,15 @@ public T accept(ParseTreeVisitor extends T> visitor) {
public final ExistsQueryContext existsQuery() throws RecognitionException {
ExistsQueryContext _localctx = new ExistsQueryContext(_ctx, getState());
- enterRule(_localctx, 18, RULE_existsQuery);
+ enterRule(_localctx, 24, RULE_existsQuery);
try {
enterOuterAlt(_localctx, 1);
{
- setState(85);
+ setState(114);
fieldName();
- setState(86);
+ setState(115);
match(COLON);
- setState(87);
+ setState(116);
match(WILDCARD);
}
}
@@ -878,34 +1163,34 @@ public T accept(ParseTreeVisitor extends T> visitor) {
public final FieldQueryContext fieldQuery() throws RecognitionException {
FieldQueryContext _localctx = new FieldQueryContext(_ctx, getState());
- enterRule(_localctx, 20, RULE_fieldQuery);
+ enterRule(_localctx, 26, RULE_fieldQuery);
try {
- setState(99);
+ setState(128);
_errHandler.sync(this);
- switch ( getInterpreter().adaptivePredict(_input,6,_ctx) ) {
+ switch ( getInterpreter().adaptivePredict(_input,8,_ctx) ) {
case 1:
enterOuterAlt(_localctx, 1);
{
- setState(89);
+ setState(118);
fieldName();
- setState(90);
+ setState(119);
match(COLON);
- setState(91);
+ setState(120);
fieldQueryValue();
}
break;
case 2:
enterOuterAlt(_localctx, 2);
{
- setState(93);
+ setState(122);
fieldName();
- setState(94);
+ setState(123);
match(COLON);
- setState(95);
+ setState(124);
match(LEFT_PARENTHESIS);
- setState(96);
+ setState(125);
fieldQueryValue();
- setState(97);
+ setState(126);
match(RIGHT_PARENTHESIS);
}
break;
@@ -950,9 +1235,9 @@ public T accept(ParseTreeVisitor extends T> visitor) {
public final FieldLessQueryContext fieldLessQuery() throws RecognitionException {
FieldLessQueryContext _localctx = new FieldLessQueryContext(_ctx, getState());
- enterRule(_localctx, 22, RULE_fieldLessQuery);
+ enterRule(_localctx, 28, RULE_fieldLessQuery);
try {
- setState(106);
+ setState(135);
_errHandler.sync(this);
switch (_input.LA(1)) {
case AND:
@@ -963,18 +1248,18 @@ public final FieldLessQueryContext fieldLessQuery() throws RecognitionException
case WILDCARD:
enterOuterAlt(_localctx, 1);
{
- setState(101);
+ setState(130);
fieldQueryValue();
}
break;
case LEFT_PARENTHESIS:
enterOuterAlt(_localctx, 2);
{
- setState(102);
+ setState(131);
match(LEFT_PARENTHESIS);
- setState(103);
+ setState(132);
fieldQueryValue();
- setState(104);
+ setState(133);
match(RIGHT_PARENTHESIS);
}
break;
@@ -1037,22 +1322,22 @@ public T accept(ParseTreeVisitor extends T> visitor) {
public final FieldQueryValueContext fieldQueryValue() throws RecognitionException {
FieldQueryValueContext _localctx = new FieldQueryValueContext(_ctx, getState());
- enterRule(_localctx, 24, RULE_fieldQueryValue);
+ enterRule(_localctx, 30, RULE_fieldQueryValue);
int _la;
try {
int _alt;
- setState(128);
+ setState(157);
_errHandler.sync(this);
- switch ( getInterpreter().adaptivePredict(_input,13,_ctx) ) {
+ switch ( getInterpreter().adaptivePredict(_input,15,_ctx) ) {
case 1:
enterOuterAlt(_localctx, 1);
{
- setState(109);
+ setState(138);
_errHandler.sync(this);
_la = _input.LA(1);
if ((((_la) & ~0x3f) == 0 && ((1L << _la) & 28L) != 0)) {
{
- setState(108);
+ setState(137);
_la = _input.LA(1);
if ( !((((_la) & ~0x3f) == 0 && ((1L << _la) & 28L) != 0)) ) {
_errHandler.recoverInline(this);
@@ -1065,7 +1350,7 @@ public final FieldQueryValueContext fieldQueryValue() throws RecognitionExceptio
}
}
- setState(112);
+ setState(141);
_errHandler.sync(this);
_alt = 1;
do {
@@ -1073,7 +1358,7 @@ public final FieldQueryValueContext fieldQueryValue() throws RecognitionExceptio
case 1:
{
{
- setState(111);
+ setState(140);
_la = _input.LA(1);
if ( !(_la==UNQUOTED_LITERAL || _la==WILDCARD) ) {
_errHandler.recoverInline(this);
@@ -1089,16 +1374,16 @@ public final FieldQueryValueContext fieldQueryValue() throws RecognitionExceptio
default:
throw new NoViableAltException(this);
}
- setState(114);
+ setState(143);
_errHandler.sync(this);
- _alt = getInterpreter().adaptivePredict(_input,9,_ctx);
+ _alt = getInterpreter().adaptivePredict(_input,11,_ctx);
} while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER );
- setState(117);
+ setState(146);
_errHandler.sync(this);
- switch ( getInterpreter().adaptivePredict(_input,10,_ctx) ) {
+ switch ( getInterpreter().adaptivePredict(_input,12,_ctx) ) {
case 1:
{
- setState(116);
+ setState(145);
_la = _input.LA(1);
if ( !((((_la) & ~0x3f) == 0 && ((1L << _la) & 28L) != 0)) ) {
_errHandler.recoverInline(this);
@@ -1116,7 +1401,7 @@ public final FieldQueryValueContext fieldQueryValue() throws RecognitionExceptio
case 2:
enterOuterAlt(_localctx, 2);
{
- setState(119);
+ setState(148);
_la = _input.LA(1);
if ( !(_la==AND || _la==OR) ) {
_errHandler.recoverInline(this);
@@ -1126,12 +1411,12 @@ public final FieldQueryValueContext fieldQueryValue() throws RecognitionExceptio
_errHandler.reportMatch(this);
consume();
}
- setState(121);
+ setState(150);
_errHandler.sync(this);
- switch ( getInterpreter().adaptivePredict(_input,11,_ctx) ) {
+ switch ( getInterpreter().adaptivePredict(_input,13,_ctx) ) {
case 1:
{
- setState(120);
+ setState(149);
_la = _input.LA(1);
if ( !((((_la) & ~0x3f) == 0 && ((1L << _la) & 28L) != 0)) ) {
_errHandler.recoverInline(this);
@@ -1149,14 +1434,14 @@ public final FieldQueryValueContext fieldQueryValue() throws RecognitionExceptio
case 3:
enterOuterAlt(_localctx, 3);
{
- setState(123);
+ setState(152);
match(NOT);
- setState(125);
+ setState(154);
_errHandler.sync(this);
- switch ( getInterpreter().adaptivePredict(_input,12,_ctx) ) {
+ switch ( getInterpreter().adaptivePredict(_input,14,_ctx) ) {
case 1:
{
- setState(124);
+ setState(153);
_la = _input.LA(1);
if ( !(_la==AND || _la==OR) ) {
_errHandler.recoverInline(this);
@@ -1174,7 +1459,7 @@ public final FieldQueryValueContext fieldQueryValue() throws RecognitionExceptio
case 4:
enterOuterAlt(_localctx, 4);
{
- setState(127);
+ setState(156);
match(QUOTED_STRING);
}
break;
@@ -1218,29 +1503,29 @@ public T accept(ParseTreeVisitor extends T> visitor) {
public final FieldNameContext fieldName() throws RecognitionException {
FieldNameContext _localctx = new FieldNameContext(_ctx, getState());
- enterRule(_localctx, 26, RULE_fieldName);
+ enterRule(_localctx, 32, RULE_fieldName);
try {
- setState(133);
+ setState(162);
_errHandler.sync(this);
switch (_input.LA(1)) {
case UNQUOTED_LITERAL:
enterOuterAlt(_localctx, 1);
{
- setState(130);
+ setState(159);
((FieldNameContext)_localctx).value = match(UNQUOTED_LITERAL);
}
break;
case QUOTED_STRING:
enterOuterAlt(_localctx, 2);
{
- setState(131);
+ setState(160);
((FieldNameContext)_localctx).value = match(QUOTED_STRING);
}
break;
case WILDCARD:
enterOuterAlt(_localctx, 3);
{
- setState(132);
+ setState(161);
((FieldNameContext)_localctx).value = match(WILDCARD);
}
break;
@@ -1263,6 +1548,8 @@ public boolean sempred(RuleContext _localctx, int ruleIndex, int predIndex) {
switch (ruleIndex) {
case 1:
return query_sempred((QueryContext)_localctx, predIndex);
+ case 5:
+ return nestedSubQuery_sempred((NestedSubQueryContext)_localctx, predIndex);
}
return true;
}
@@ -1273,87 +1560,117 @@ private boolean query_sempred(QueryContext _localctx, int predIndex) {
}
return true;
}
+ private boolean nestedSubQuery_sempred(NestedSubQueryContext _localctx, int predIndex) {
+ switch (predIndex) {
+ case 1:
+ return precpred(_ctx, 2);
+ }
+ return true;
+ }
public static final String _serializedATN =
- "\u0004\u0001\u0010\u0088\u0002\u0000\u0007\u0000\u0002\u0001\u0007\u0001"+
+ "\u0004\u0001\u0010\u00a5\u0002\u0000\u0007\u0000\u0002\u0001\u0007\u0001"+
"\u0002\u0002\u0007\u0002\u0002\u0003\u0007\u0003\u0002\u0004\u0007\u0004"+
"\u0002\u0005\u0007\u0005\u0002\u0006\u0007\u0006\u0002\u0007\u0007\u0007"+
"\u0002\b\u0007\b\u0002\t\u0007\t\u0002\n\u0007\n\u0002\u000b\u0007\u000b"+
- "\u0002\f\u0007\f\u0002\r\u0007\r\u0001\u0000\u0003\u0000\u001e\b\u0000"+
- "\u0001\u0000\u0001\u0000\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001"+
- "\u0001\u0001\u0001\u0001\u0005\u0001(\b\u0001\n\u0001\f\u0001+\t\u0001"+
- "\u0001\u0002\u0001\u0002\u0001\u0002\u0001\u0002\u0001\u0002\u0001\u0002"+
- "\u0001\u0002\u0001\u0002\u0003\u00025\b\u0002\u0001\u0003\u0001\u0003"+
- "\u0001\u0003\u0001\u0004\u0001\u0004\u0001\u0004\u0001\u0004\u0001\u0004"+
- "\u0001\u0004\u0001\u0005\u0001\u0005\u0003\u0005B\b\u0005\u0001\u0005"+
- "\u0001\u0005\u0001\u0006\u0001\u0006\u0001\u0006\u0001\u0006\u0001\u0007"+
- "\u0001\u0007\u0001\u0007\u0001\u0007\u0001\b\u0004\bO\b\b\u000b\b\f\b"+
- "P\u0001\b\u0003\bT\b\b\u0001\t\u0001\t\u0001\t\u0001\t\u0001\n\u0001\n"+
- "\u0001\n\u0001\n\u0001\n\u0001\n\u0001\n\u0001\n\u0001\n\u0001\n\u0003"+
- "\nd\b\n\u0001\u000b\u0001\u000b\u0001\u000b\u0001\u000b\u0001\u000b\u0003"+
- "\u000bk\b\u000b\u0001\f\u0003\fn\b\f\u0001\f\u0004\fq\b\f\u000b\f\f\f"+
- "r\u0001\f\u0003\fv\b\f\u0001\f\u0001\f\u0003\fz\b\f\u0001\f\u0001\f\u0003"+
- "\f~\b\f\u0001\f\u0003\f\u0081\b\f\u0001\r\u0001\r\u0001\r\u0003\r\u0086"+
- "\b\r\u0001\r\u0000\u0001\u0002\u000e\u0000\u0002\u0004\u0006\b\n\f\u000e"+
- "\u0010\u0012\u0014\u0016\u0018\u001a\u0000\u0004\u0001\u0000\u0002\u0003"+
- "\u0001\u0000\u0006\t\u0002\u0000\u000e\u000e\u0010\u0010\u0001\u0000\u0002"+
- "\u0004\u0091\u0000\u001d\u0001\u0000\u0000\u0000\u0002!\u0001\u0000\u0000"+
- "\u0000\u00044\u0001\u0000\u0000\u0000\u00066\u0001\u0000\u0000\u0000\b"+
- "9\u0001\u0000\u0000\u0000\nA\u0001\u0000\u0000\u0000\fE\u0001\u0000\u0000"+
- "\u0000\u000eI\u0001\u0000\u0000\u0000\u0010S\u0001\u0000\u0000\u0000\u0012"+
- "U\u0001\u0000\u0000\u0000\u0014c\u0001\u0000\u0000\u0000\u0016j\u0001"+
- "\u0000\u0000\u0000\u0018\u0080\u0001\u0000\u0000\u0000\u001a\u0085\u0001"+
- "\u0000\u0000\u0000\u001c\u001e\u0003\u0002\u0001\u0000\u001d\u001c\u0001"+
- "\u0000\u0000\u0000\u001d\u001e\u0001\u0000\u0000\u0000\u001e\u001f\u0001"+
- "\u0000\u0000\u0000\u001f \u0005\u0000\u0000\u0001 \u0001\u0001\u0000\u0000"+
- "\u0000!\"\u0006\u0001\uffff\uffff\u0000\"#\u0003\u0004\u0002\u0000#)\u0001"+
- "\u0000\u0000\u0000$%\n\u0002\u0000\u0000%&\u0007\u0000\u0000\u0000&(\u0003"+
- "\u0002\u0001\u0002\'$\u0001\u0000\u0000\u0000(+\u0001\u0000\u0000\u0000"+
- ")\'\u0001\u0000\u0000\u0000)*\u0001\u0000\u0000\u0000*\u0003\u0001\u0000"+
- "\u0000\u0000+)\u0001\u0000\u0000\u0000,5\u0003\u0006\u0003\u0000-5\u0003"+
- "\b\u0004\u0000.5\u0003\f\u0006\u0000/5\u0003\n\u0005\u000005\u0003\u0012"+
- "\t\u000015\u0003\u000e\u0007\u000025\u0003\u0014\n\u000035\u0003\u0016"+
- "\u000b\u00004,\u0001\u0000\u0000\u00004-\u0001\u0000\u0000\u00004.\u0001"+
- "\u0000\u0000\u00004/\u0001\u0000\u0000\u000040\u0001\u0000\u0000\u0000"+
- "41\u0001\u0000\u0000\u000042\u0001\u0000\u0000\u000043\u0001\u0000\u0000"+
- "\u00005\u0005\u0001\u0000\u0000\u000067\u0005\u0004\u0000\u000078\u0003"+
- "\u0004\u0002\u00008\u0007\u0001\u0000\u0000\u00009:\u0003\u001a\r\u0000"+
- ":;\u0005\u0005\u0000\u0000;<\u0005\f\u0000\u0000<=\u0003\u0002\u0001\u0000"+
- "=>\u0005\r\u0000\u0000>\t\u0001\u0000\u0000\u0000?@\u0005\u0010\u0000"+
- "\u0000@B\u0005\u0005\u0000\u0000A?\u0001\u0000\u0000\u0000AB\u0001\u0000"+
- "\u0000\u0000BC\u0001\u0000\u0000\u0000CD\u0005\u0010\u0000\u0000D\u000b"+
- "\u0001\u0000\u0000\u0000EF\u0005\n\u0000\u0000FG\u0003\u0002\u0001\u0000"+
- "GH\u0005\u000b\u0000\u0000H\r\u0001\u0000\u0000\u0000IJ\u0003\u001a\r"+
- "\u0000JK\u0007\u0001\u0000\u0000KL\u0003\u0010\b\u0000L\u000f\u0001\u0000"+
- "\u0000\u0000MO\u0007\u0002\u0000\u0000NM\u0001\u0000\u0000\u0000OP\u0001"+
- "\u0000\u0000\u0000PN\u0001\u0000\u0000\u0000PQ\u0001\u0000\u0000\u0000"+
- "QT\u0001\u0000\u0000\u0000RT\u0005\u000f\u0000\u0000SN\u0001\u0000\u0000"+
- "\u0000SR\u0001\u0000\u0000\u0000T\u0011\u0001\u0000\u0000\u0000UV\u0003"+
- "\u001a\r\u0000VW\u0005\u0005\u0000\u0000WX\u0005\u0010\u0000\u0000X\u0013"+
- "\u0001\u0000\u0000\u0000YZ\u0003\u001a\r\u0000Z[\u0005\u0005\u0000\u0000"+
- "[\\\u0003\u0018\f\u0000\\d\u0001\u0000\u0000\u0000]^\u0003\u001a\r\u0000"+
- "^_\u0005\u0005\u0000\u0000_`\u0005\n\u0000\u0000`a\u0003\u0018\f\u0000"+
- "ab\u0005\u000b\u0000\u0000bd\u0001\u0000\u0000\u0000cY\u0001\u0000\u0000"+
- "\u0000c]\u0001\u0000\u0000\u0000d\u0015\u0001\u0000\u0000\u0000ek\u0003"+
- "\u0018\f\u0000fg\u0005\n\u0000\u0000gh\u0003\u0018\f\u0000hi\u0005\u000b"+
- "\u0000\u0000ik\u0001\u0000\u0000\u0000je\u0001\u0000\u0000\u0000jf\u0001"+
- "\u0000\u0000\u0000k\u0017\u0001\u0000\u0000\u0000ln\u0007\u0003\u0000"+
- "\u0000ml\u0001\u0000\u0000\u0000mn\u0001\u0000\u0000\u0000np\u0001\u0000"+
- "\u0000\u0000oq\u0007\u0002\u0000\u0000po\u0001\u0000\u0000\u0000qr\u0001"+
- "\u0000\u0000\u0000rp\u0001\u0000\u0000\u0000rs\u0001\u0000\u0000\u0000"+
- "su\u0001\u0000\u0000\u0000tv\u0007\u0003\u0000\u0000ut\u0001\u0000\u0000"+
- "\u0000uv\u0001\u0000\u0000\u0000v\u0081\u0001\u0000\u0000\u0000wy\u0007"+
- "\u0000\u0000\u0000xz\u0007\u0003\u0000\u0000yx\u0001\u0000\u0000\u0000"+
- "yz\u0001\u0000\u0000\u0000z\u0081\u0001\u0000\u0000\u0000{}\u0005\u0004"+
- "\u0000\u0000|~\u0007\u0000\u0000\u0000}|\u0001\u0000\u0000\u0000}~\u0001"+
- "\u0000\u0000\u0000~\u0081\u0001\u0000\u0000\u0000\u007f\u0081\u0005\u000f"+
- "\u0000\u0000\u0080m\u0001\u0000\u0000\u0000\u0080w\u0001\u0000\u0000\u0000"+
- "\u0080{\u0001\u0000\u0000\u0000\u0080\u007f\u0001\u0000\u0000\u0000\u0081"+
- "\u0019\u0001\u0000\u0000\u0000\u0082\u0086\u0005\u000e\u0000\u0000\u0083"+
- "\u0086\u0005\u000f\u0000\u0000\u0084\u0086\u0005\u0010\u0000\u0000\u0085"+
- "\u0082\u0001\u0000\u0000\u0000\u0085\u0083\u0001\u0000\u0000\u0000\u0085"+
- "\u0084\u0001\u0000\u0000\u0000\u0086\u001b\u0001\u0000\u0000\u0000\u000f"+
- "\u001d)4APScjmruy}\u0080\u0085";
+ "\u0002\f\u0007\f\u0002\r\u0007\r\u0002\u000e\u0007\u000e\u0002\u000f\u0007"+
+ "\u000f\u0002\u0010\u0007\u0010\u0001\u0000\u0003\u0000$\b\u0000\u0001"+
+ "\u0000\u0001\u0000\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001"+
+ "\u0001\u0001\u0001\u0005\u0001.\b\u0001\n\u0001\f\u00011\t\u0001\u0001"+
+ "\u0002\u0001\u0002\u0001\u0002\u0001\u0002\u0001\u0002\u0001\u0002\u0001"+
+ "\u0002\u0001\u0002\u0003\u0002;\b\u0002\u0001\u0003\u0001\u0003\u0001"+
+ "\u0003\u0001\u0004\u0001\u0004\u0001\u0004\u0001\u0004\u0001\u0004\u0001"+
+ "\u0004\u0001\u0005\u0001\u0005\u0001\u0005\u0001\u0005\u0001\u0005\u0001"+
+ "\u0005\u0005\u0005L\b\u0005\n\u0005\f\u0005O\t\u0005\u0001\u0006\u0001"+
+ "\u0006\u0001\u0006\u0001\u0006\u0001\u0006\u0001\u0006\u0003\u0006W\b"+
+ "\u0006\u0001\u0007\u0001\u0007\u0001\u0007\u0001\u0007\u0001\b\u0001\b"+
+ "\u0003\b_\b\b\u0001\b\u0001\b\u0001\t\u0001\t\u0001\t\u0001\t\u0001\n"+
+ "\u0001\n\u0001\n\u0001\n\u0001\u000b\u0004\u000bl\b\u000b\u000b\u000b"+
+ "\f\u000bm\u0001\u000b\u0003\u000bq\b\u000b\u0001\f\u0001\f\u0001\f\u0001"+
+ "\f\u0001\r\u0001\r\u0001\r\u0001\r\u0001\r\u0001\r\u0001\r\u0001\r\u0001"+
+ "\r\u0001\r\u0003\r\u0081\b\r\u0001\u000e\u0001\u000e\u0001\u000e\u0001"+
+ "\u000e\u0001\u000e\u0003\u000e\u0088\b\u000e\u0001\u000f\u0003\u000f\u008b"+
+ "\b\u000f\u0001\u000f\u0004\u000f\u008e\b\u000f\u000b\u000f\f\u000f\u008f"+
+ "\u0001\u000f\u0003\u000f\u0093\b\u000f\u0001\u000f\u0001\u000f\u0003\u000f"+
+ "\u0097\b\u000f\u0001\u000f\u0001\u000f\u0003\u000f\u009b\b\u000f\u0001"+
+ "\u000f\u0003\u000f\u009e\b\u000f\u0001\u0010\u0001\u0010\u0001\u0010\u0003"+
+ "\u0010\u00a3\b\u0010\u0001\u0010\u0000\u0002\u0002\n\u0011\u0000\u0002"+
+ "\u0004\u0006\b\n\f\u000e\u0010\u0012\u0014\u0016\u0018\u001a\u001c\u001e"+
+ " \u0000\u0004\u0001\u0000\u0002\u0003\u0001\u0000\u0006\t\u0002\u0000"+
+ "\u000e\u000e\u0010\u0010\u0001\u0000\u0002\u0004\u00b1\u0000#\u0001\u0000"+
+ "\u0000\u0000\u0002\'\u0001\u0000\u0000\u0000\u0004:\u0001\u0000\u0000"+
+ "\u0000\u0006<\u0001\u0000\u0000\u0000\b?\u0001\u0000\u0000\u0000\nE\u0001"+
+ "\u0000\u0000\u0000\fV\u0001\u0000\u0000\u0000\u000eX\u0001\u0000\u0000"+
+ "\u0000\u0010^\u0001\u0000\u0000\u0000\u0012b\u0001\u0000\u0000\u0000\u0014"+
+ "f\u0001\u0000\u0000\u0000\u0016p\u0001\u0000\u0000\u0000\u0018r\u0001"+
+ "\u0000\u0000\u0000\u001a\u0080\u0001\u0000\u0000\u0000\u001c\u0087\u0001"+
+ "\u0000\u0000\u0000\u001e\u009d\u0001\u0000\u0000\u0000 \u00a2\u0001\u0000"+
+ "\u0000\u0000\"$\u0003\u0002\u0001\u0000#\"\u0001\u0000\u0000\u0000#$\u0001"+
+ "\u0000\u0000\u0000$%\u0001\u0000\u0000\u0000%&\u0005\u0000\u0000\u0001"+
+ "&\u0001\u0001\u0000\u0000\u0000\'(\u0006\u0001\uffff\uffff\u0000()\u0003"+
+ "\u0004\u0002\u0000)/\u0001\u0000\u0000\u0000*+\n\u0002\u0000\u0000+,\u0007"+
+ "\u0000\u0000\u0000,.\u0003\u0002\u0001\u0002-*\u0001\u0000\u0000\u0000"+
+ ".1\u0001\u0000\u0000\u0000/-\u0001\u0000\u0000\u0000/0\u0001\u0000\u0000"+
+ "\u00000\u0003\u0001\u0000\u0000\u00001/\u0001\u0000\u0000\u00002;\u0003"+
+ "\u0006\u0003\u00003;\u0003\b\u0004\u00004;\u0003\u0012\t\u00005;\u0003"+
+ "\u0010\b\u00006;\u0003\u0018\f\u00007;\u0003\u0014\n\u00008;\u0003\u001a"+
+ "\r\u00009;\u0003\u001c\u000e\u0000:2\u0001\u0000\u0000\u0000:3\u0001\u0000"+
+ "\u0000\u0000:4\u0001\u0000\u0000\u0000:5\u0001\u0000\u0000\u0000:6\u0001"+
+ "\u0000\u0000\u0000:7\u0001\u0000\u0000\u0000:8\u0001\u0000\u0000\u0000"+
+ ":9\u0001\u0000\u0000\u0000;\u0005\u0001\u0000\u0000\u0000<=\u0005\u0004"+
+ "\u0000\u0000=>\u0003\u0004\u0002\u0000>\u0007\u0001\u0000\u0000\u0000"+
+ "?@\u0003 \u0010\u0000@A\u0005\u0005\u0000\u0000AB\u0005\f\u0000\u0000"+
+ "BC\u0003\n\u0005\u0000CD\u0005\r\u0000\u0000D\t\u0001\u0000\u0000\u0000"+
+ "EF\u0006\u0005\uffff\uffff\u0000FG\u0003\f\u0006\u0000GM\u0001\u0000\u0000"+
+ "\u0000HI\n\u0002\u0000\u0000IJ\u0007\u0000\u0000\u0000JL\u0003\n\u0005"+
+ "\u0002KH\u0001\u0000\u0000\u0000LO\u0001\u0000\u0000\u0000MK\u0001\u0000"+
+ "\u0000\u0000MN\u0001\u0000\u0000\u0000N\u000b\u0001\u0000\u0000\u0000"+
+ "OM\u0001\u0000\u0000\u0000PW\u0003\u0006\u0003\u0000QW\u0003\b\u0004\u0000"+
+ "RW\u0003\u000e\u0007\u0000SW\u0003\u0018\f\u0000TW\u0003\u0014\n\u0000"+
+ "UW\u0003\u001a\r\u0000VP\u0001\u0000\u0000\u0000VQ\u0001\u0000\u0000\u0000"+
+ "VR\u0001\u0000\u0000\u0000VS\u0001\u0000\u0000\u0000VT\u0001\u0000\u0000"+
+ "\u0000VU\u0001\u0000\u0000\u0000W\r\u0001\u0000\u0000\u0000XY\u0005\n"+
+ "\u0000\u0000YZ\u0003\n\u0005\u0000Z[\u0005\u000b\u0000\u0000[\u000f\u0001"+
+ "\u0000\u0000\u0000\\]\u0005\u0010\u0000\u0000]_\u0005\u0005\u0000\u0000"+
+ "^\\\u0001\u0000\u0000\u0000^_\u0001\u0000\u0000\u0000_`\u0001\u0000\u0000"+
+ "\u0000`a\u0005\u0010\u0000\u0000a\u0011\u0001\u0000\u0000\u0000bc\u0005"+
+ "\n\u0000\u0000cd\u0003\u0002\u0001\u0000de\u0005\u000b\u0000\u0000e\u0013"+
+ "\u0001\u0000\u0000\u0000fg\u0003 \u0010\u0000gh\u0007\u0001\u0000\u0000"+
+ "hi\u0003\u0016\u000b\u0000i\u0015\u0001\u0000\u0000\u0000jl\u0007\u0002"+
+ "\u0000\u0000kj\u0001\u0000\u0000\u0000lm\u0001\u0000\u0000\u0000mk\u0001"+
+ "\u0000\u0000\u0000mn\u0001\u0000\u0000\u0000nq\u0001\u0000\u0000\u0000"+
+ "oq\u0005\u000f\u0000\u0000pk\u0001\u0000\u0000\u0000po\u0001\u0000\u0000"+
+ "\u0000q\u0017\u0001\u0000\u0000\u0000rs\u0003 \u0010\u0000st\u0005\u0005"+
+ "\u0000\u0000tu\u0005\u0010\u0000\u0000u\u0019\u0001\u0000\u0000\u0000"+
+ "vw\u0003 \u0010\u0000wx\u0005\u0005\u0000\u0000xy\u0003\u001e\u000f\u0000"+
+ "y\u0081\u0001\u0000\u0000\u0000z{\u0003 \u0010\u0000{|\u0005\u0005\u0000"+
+ "\u0000|}\u0005\n\u0000\u0000}~\u0003\u001e\u000f\u0000~\u007f\u0005\u000b"+
+ "\u0000\u0000\u007f\u0081\u0001\u0000\u0000\u0000\u0080v\u0001\u0000\u0000"+
+ "\u0000\u0080z\u0001\u0000\u0000\u0000\u0081\u001b\u0001\u0000\u0000\u0000"+
+ "\u0082\u0088\u0003\u001e\u000f\u0000\u0083\u0084\u0005\n\u0000\u0000\u0084"+
+ "\u0085\u0003\u001e\u000f\u0000\u0085\u0086\u0005\u000b\u0000\u0000\u0086"+
+ "\u0088\u0001\u0000\u0000\u0000\u0087\u0082\u0001\u0000\u0000\u0000\u0087"+
+ "\u0083\u0001\u0000\u0000\u0000\u0088\u001d\u0001\u0000\u0000\u0000\u0089"+
+ "\u008b\u0007\u0003\u0000\u0000\u008a\u0089\u0001\u0000\u0000\u0000\u008a"+
+ "\u008b\u0001\u0000\u0000\u0000\u008b\u008d\u0001\u0000\u0000\u0000\u008c"+
+ "\u008e\u0007\u0002\u0000\u0000\u008d\u008c\u0001\u0000\u0000\u0000\u008e"+
+ "\u008f\u0001\u0000\u0000\u0000\u008f\u008d\u0001\u0000\u0000\u0000\u008f"+
+ "\u0090\u0001\u0000\u0000\u0000\u0090\u0092\u0001\u0000\u0000\u0000\u0091"+
+ "\u0093\u0007\u0003\u0000\u0000\u0092\u0091\u0001\u0000\u0000\u0000\u0092"+
+ "\u0093\u0001\u0000\u0000\u0000\u0093\u009e\u0001\u0000\u0000\u0000\u0094"+
+ "\u0096\u0007\u0000\u0000\u0000\u0095\u0097\u0007\u0003\u0000\u0000\u0096"+
+ "\u0095\u0001\u0000\u0000\u0000\u0096\u0097\u0001\u0000\u0000\u0000\u0097"+
+ "\u009e\u0001\u0000\u0000\u0000\u0098\u009a\u0005\u0004\u0000\u0000\u0099"+
+ "\u009b\u0007\u0000\u0000\u0000\u009a\u0099\u0001\u0000\u0000\u0000\u009a"+
+ "\u009b\u0001\u0000\u0000\u0000\u009b\u009e\u0001\u0000\u0000\u0000\u009c"+
+ "\u009e\u0005\u000f\u0000\u0000\u009d\u008a\u0001\u0000\u0000\u0000\u009d"+
+ "\u0094\u0001\u0000\u0000\u0000\u009d\u0098\u0001\u0000\u0000\u0000\u009d"+
+ "\u009c\u0001\u0000\u0000\u0000\u009e\u001f\u0001\u0000\u0000\u0000\u009f"+
+ "\u00a3\u0005\u000e\u0000\u0000\u00a0\u00a3\u0005\u000f\u0000\u0000\u00a1"+
+ "\u00a3\u0005\u0010\u0000\u0000\u00a2\u009f\u0001\u0000\u0000\u0000\u00a2"+
+ "\u00a0\u0001\u0000\u0000\u0000\u00a2\u00a1\u0001\u0000\u0000\u0000\u00a3"+
+ "!\u0001\u0000\u0000\u0000\u0011#/:MV^mp\u0080\u0087\u008a\u008f\u0092"+
+ "\u0096\u009a\u009d\u00a2";
public static final ATN _ATN =
new ATNDeserializer().deserialize(_serializedATN.toCharArray());
static {
diff --git a/x-pack/plugin/kql/src/main/java/org/elasticsearch/xpack/kql/parser/KqlBaseVisitor.java b/x-pack/plugin/kql/src/main/java/org/elasticsearch/xpack/kql/parser/KqlBaseVisitor.java
index 18ef8f389195..8200bfe0da25 100644
--- a/x-pack/plugin/kql/src/main/java/org/elasticsearch/xpack/kql/parser/KqlBaseVisitor.java
+++ b/x-pack/plugin/kql/src/main/java/org/elasticsearch/xpack/kql/parser/KqlBaseVisitor.java
@@ -56,6 +56,32 @@ interface KqlBaseVisitor extends ParseTreeVisitor {
* @return the visitor result
*/
T visitNestedQuery(KqlBaseParser.NestedQueryContext ctx);
+ /**
+ * Visit a parse tree produced by the {@code booleanNestedQuery}
+ * labeled alternative in {@link KqlBaseParser#nestedSubQuery}.
+ * @param ctx the parse tree
+ * @return the visitor result
+ */
+ T visitBooleanNestedQuery(KqlBaseParser.BooleanNestedQueryContext ctx);
+ /**
+ * Visit a parse tree produced by the {@code defaultNestedQuery}
+ * labeled alternative in {@link KqlBaseParser#nestedSubQuery}.
+ * @param ctx the parse tree
+ * @return the visitor result
+ */
+ T visitDefaultNestedQuery(KqlBaseParser.DefaultNestedQueryContext ctx);
+ /**
+ * Visit a parse tree produced by {@link KqlBaseParser#nestedSimpleSubQuery}.
+ * @param ctx the parse tree
+ * @return the visitor result
+ */
+ T visitNestedSimpleSubQuery(KqlBaseParser.NestedSimpleSubQueryContext ctx);
+ /**
+ * Visit a parse tree produced by {@link KqlBaseParser#nestedParenthesizedQuery}.
+ * @param ctx the parse tree
+ * @return the visitor result
+ */
+ T visitNestedParenthesizedQuery(KqlBaseParser.NestedParenthesizedQueryContext ctx);
/**
* Visit a parse tree produced by {@link KqlBaseParser#matchAllQuery}.
* @param ctx the parse tree
diff --git a/x-pack/plugin/kql/src/main/java/org/elasticsearch/xpack/kql/parser/KqlParsingContext.java b/x-pack/plugin/kql/src/main/java/org/elasticsearch/xpack/kql/parser/KqlParsingContext.java
index 5f88080fb3ed..30740833ee40 100644
--- a/x-pack/plugin/kql/src/main/java/org/elasticsearch/xpack/kql/parser/KqlParsingContext.java
+++ b/x-pack/plugin/kql/src/main/java/org/elasticsearch/xpack/kql/parser/KqlParsingContext.java
@@ -11,11 +11,18 @@
import org.elasticsearch.index.mapper.DateFieldMapper;
import org.elasticsearch.index.mapper.KeywordFieldMapper;
import org.elasticsearch.index.mapper.MappedFieldType;
+import org.elasticsearch.index.mapper.NestedLookup;
+import org.elasticsearch.index.mapper.NestedObjectMapper;
import org.elasticsearch.index.query.QueryRewriteContext;
+import org.elasticsearch.index.query.support.NestedScope;
import java.time.ZoneId;
import java.util.List;
+import java.util.Map;
import java.util.Set;
+import java.util.function.Supplier;
+
+import static org.elasticsearch.common.Strings.format;
public class KqlParsingContext {
@@ -32,10 +39,11 @@ public static Builder builder(QueryRewriteContext queryRewriteContext) {
return new Builder(queryRewriteContext);
}
- private QueryRewriteContext queryRewriteContext;
+ private final QueryRewriteContext queryRewriteContext;
private final boolean caseInsensitive;
private final ZoneId timeZone;
private final String defaultField;
+ private final NestedScope nestedScope = new NestedScope();
public KqlParsingContext(QueryRewriteContext queryRewriteContext, boolean caseInsensitive, ZoneId timeZone, String defaultField) {
this.queryRewriteContext = queryRewriteContext;
@@ -56,9 +64,17 @@ public String defaultField() {
return defaultField;
}
+ public String nestedPath(String fieldName) {
+ return nestedLookup().getNestedParent(fieldName);
+ }
+
+ public boolean isNestedField(String fieldName) {
+ return nestedMappers().containsKey(fullFieldName(fieldName));
+ }
+
public Set resolveFieldNames(String fieldNamePattern) {
assert fieldNamePattern != null && fieldNamePattern.isEmpty() == false : "fieldNamePattern cannot be null or empty";
- return queryRewriteContext.getMatchingFieldNames(fieldNamePattern);
+ return queryRewriteContext.getMatchingFieldNames(fullFieldName(fieldNamePattern));
}
public Set resolveDefaultFieldNames() {
@@ -89,6 +105,38 @@ public boolean isSearchableField(String fieldName) {
return isSearchableField(fieldName, fieldType(fieldName));
}
+ public NestedScope nestedScope() {
+ return nestedScope;
+ }
+
+ public T withNestedPath(String nestedFieldName, Supplier supplier) {
+ assert isNestedField(nestedFieldName);
+ nestedScope.nextLevel(nestedMappers().get(fullFieldName(nestedFieldName)));
+ T result = supplier.get();
+ nestedScope.previousLevel();
+ return result;
+ }
+
+ public String currentNestedPath() {
+ return nestedScope().getObjectMapper() != null ? nestedScope().getObjectMapper().fullPath() : null;
+ }
+
+ public String fullFieldName(String fieldName) {
+ if (nestedScope.getObjectMapper() == null) {
+ return fieldName;
+ }
+
+ return format("%s.%s", nestedScope.getObjectMapper().fullPath(), fieldName);
+ }
+
+ private NestedLookup nestedLookup() {
+ return queryRewriteContext.getMappingLookup().nestedLookup();
+ }
+
+ private Map nestedMappers() {
+ return nestedLookup().getNestedMappers();
+ }
+
public static class Builder {
private final QueryRewriteContext queryRewriteContext;
private boolean caseInsensitive = true;
diff --git a/x-pack/plugin/kql/src/test/java/org/elasticsearch/xpack/kql/parser/AbstractKqlParserTestCase.java b/x-pack/plugin/kql/src/test/java/org/elasticsearch/xpack/kql/parser/AbstractKqlParserTestCase.java
index 588e60bd4dd7..e6e4e20cfd3c 100644
--- a/x-pack/plugin/kql/src/test/java/org/elasticsearch/xpack/kql/parser/AbstractKqlParserTestCase.java
+++ b/x-pack/plugin/kql/src/test/java/org/elasticsearch/xpack/kql/parser/AbstractKqlParserTestCase.java
@@ -46,11 +46,9 @@
import static org.hamcrest.Matchers.equalTo;
public abstract class AbstractKqlParserTestCase extends AbstractBuilderTestCase {
-
protected static final String SUPPORTED_QUERY_FILE_PATH = "/supported-queries";
protected static final String UNSUPPORTED_QUERY_FILE_PATH = "/unsupported-queries";
protected static final Predicate BOOLEAN_QUERY_FILTER = (q) -> q.matches("(?i)[^{]*[^\\\\]*(NOT|AND|OR)[^}]*");
-
protected static final String NESTED_FIELD_NAME = "mapped_nested";
@Override
diff --git a/x-pack/plugin/kql/src/test/java/org/elasticsearch/xpack/kql/parser/KqlNestedFieldQueryTests.java b/x-pack/plugin/kql/src/test/java/org/elasticsearch/xpack/kql/parser/KqlNestedFieldQueryTests.java
new file mode 100644
index 000000000000..5660945fa0db
--- /dev/null
+++ b/x-pack/plugin/kql/src/test/java/org/elasticsearch/xpack/kql/parser/KqlNestedFieldQueryTests.java
@@ -0,0 +1,297 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+package org.elasticsearch.xpack.kql.parser;
+
+import org.elasticsearch.index.query.BoolQueryBuilder;
+import org.elasticsearch.index.query.MatchQueryBuilder;
+import org.elasticsearch.index.query.NestedQueryBuilder;
+import org.elasticsearch.index.query.QueryBuilder;
+import org.elasticsearch.index.query.RangeQueryBuilder;
+import org.elasticsearch.index.query.TermQueryBuilder;
+import org.elasticsearch.test.ESTestCase;
+import org.hamcrest.Matchers;
+
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import static org.elasticsearch.common.Strings.format;
+import static org.hamcrest.Matchers.empty;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.hasSize;
+
+public class KqlNestedFieldQueryTests extends AbstractKqlParserTestCase {
+ public void testInvalidNestedFieldName() {
+ for (String invalidFieldName : List.of(OBJECT_FIELD_NAME, TEXT_FIELD_NAME, "not_a_field", "mapped_nest*")) {
+ KqlParsingException e = assertThrows(
+ KqlParsingException.class,
+ () -> parseKqlQuery(format("%s : { %s: foo AND %s < 10 } ", invalidFieldName, TEXT_FIELD_NAME, INT_FIELD_NAME))
+ );
+ assertThat(e.getMessage(), Matchers.containsString(invalidFieldName));
+ assertThat(e.getMessage(), Matchers.containsString("is not a valid nested field name"));
+ }
+ }
+
+ public void testInlineNestedFieldMatchTextQuery() {
+ for (String fieldName : List.of(TEXT_FIELD_NAME, INT_FIELD_NAME)) {
+ {
+ // Querying a nested text subfield.
+ String nestedFieldName = format("%s.%s", NESTED_FIELD_NAME, fieldName);
+ String searchTerms = randomSearchTerms();
+ String kqlQueryString = format("%s: %s", nestedFieldName, searchTerms);
+
+ NestedQueryBuilder nestedQuery = asInstanceOf(NestedQueryBuilder.class, parseKqlQuery(kqlQueryString));
+
+ assertThat(nestedQuery.path(), equalTo(NESTED_FIELD_NAME));
+ assertMatchQueryBuilder(nestedQuery.query(), nestedFieldName, searchTerms);
+ }
+
+ {
+ // Several levels of nested fields.
+ String nestedFieldName = format("%s.%s.%s", NESTED_FIELD_NAME, NESTED_FIELD_NAME, fieldName);
+ String searchTerms = randomSearchTerms();
+ String kqlQueryString = format("%s: %s", nestedFieldName, searchTerms);
+
+ NestedQueryBuilder nestedQuery = asInstanceOf(NestedQueryBuilder.class, parseKqlQuery(kqlQueryString));
+ assertThat(nestedQuery.path(), equalTo(NESTED_FIELD_NAME));
+
+ NestedQueryBuilder nestedSubQuery = asInstanceOf(NestedQueryBuilder.class, nestedQuery.query());
+ assertThat(nestedSubQuery.path(), equalTo(format("%s.%s", NESTED_FIELD_NAME, NESTED_FIELD_NAME)));
+
+ assertMatchQueryBuilder(nestedSubQuery.query(), nestedFieldName, searchTerms);
+ }
+ }
+ }
+
+ public void testInlineNestedFieldMatchKeywordFieldQuery() {
+ {
+ // Querying a nested text subfield.
+ String nestedFieldName = format("%s.%s", NESTED_FIELD_NAME, KEYWORD_FIELD_NAME);
+ String searchTerms = randomSearchTerms();
+ String kqlQueryString = format("%s: %s", nestedFieldName, searchTerms);
+
+ NestedQueryBuilder nestedQuery = asInstanceOf(NestedQueryBuilder.class, parseKqlQuery(kqlQueryString));
+
+ assertThat(nestedQuery.path(), equalTo(NESTED_FIELD_NAME));
+ assertTermQueryBuilder(nestedQuery.query(), nestedFieldName, searchTerms);
+ }
+
+ {
+ // Several levels of nested fields.
+ String nestedFieldName = format("%s.%s.%s", NESTED_FIELD_NAME, NESTED_FIELD_NAME, KEYWORD_FIELD_NAME);
+ String searchTerms = randomSearchTerms();
+ String kqlQueryString = format("%s: %s", nestedFieldName, searchTerms);
+
+ NestedQueryBuilder nestedQuery = asInstanceOf(NestedQueryBuilder.class, parseKqlQuery(kqlQueryString));
+ assertThat(nestedQuery.path(), equalTo(NESTED_FIELD_NAME));
+
+ NestedQueryBuilder nestedSubQuery = asInstanceOf(NestedQueryBuilder.class, nestedQuery.query());
+ assertThat(nestedSubQuery.path(), equalTo(format("%s.%s", NESTED_FIELD_NAME, NESTED_FIELD_NAME)));
+
+ assertTermQueryBuilder(nestedSubQuery.query(), nestedFieldName, searchTerms);
+ }
+ }
+
+ public void testInlineNestedFieldRangeQuery() {
+ {
+ // Querying a nested text subfield.
+ String nestedFieldName = format("%s.%s", NESTED_FIELD_NAME, INT_FIELD_NAME);
+ String operator = randomFrom(">", ">=", "<", "<=");
+ String kqlQueryString = format("%s %s %s", nestedFieldName, operator, randomDouble());
+
+ NestedQueryBuilder nestedQuery = asInstanceOf(NestedQueryBuilder.class, parseKqlQuery(kqlQueryString));
+
+ assertThat(nestedQuery.path(), equalTo(NESTED_FIELD_NAME));
+ assertRangeQueryBuilder(nestedQuery.query(), nestedFieldName, rangeQueryBuilder -> {});
+ }
+
+ {
+ // Several levels of nested fields.
+ String nestedFieldName = format("%s.%s.%s", NESTED_FIELD_NAME, NESTED_FIELD_NAME, INT_FIELD_NAME);
+ String operator = randomFrom(">", ">=", "<", "<=");
+ String kqlQueryString = format("%s %s %s", nestedFieldName, operator, randomDouble());
+
+ NestedQueryBuilder nestedQuery = asInstanceOf(NestedQueryBuilder.class, parseKqlQuery(kqlQueryString));
+ assertThat(nestedQuery.path(), equalTo(NESTED_FIELD_NAME));
+
+ NestedQueryBuilder nestedSubQuery = asInstanceOf(NestedQueryBuilder.class, nestedQuery.query());
+ assertThat(nestedSubQuery.path(), equalTo(format("%s.%s", NESTED_FIELD_NAME, NESTED_FIELD_NAME)));
+
+ assertRangeQueryBuilder(nestedSubQuery.query(), nestedFieldName, rangeQueryBuilder -> {});
+ }
+ }
+
+ public void testNestedQuerySyntax() {
+ // Single word - Keyword & text field
+ List.of(KEYWORD_FIELD_NAME, TEXT_FIELD_NAME)
+ .forEach(
+ fieldName -> assertThat(
+ parseKqlQuery(format("%s : { %s : %s }", NESTED_FIELD_NAME, fieldName, "foo")),
+ equalTo(parseKqlQuery(format("%s.%s : %s", NESTED_FIELD_NAME, fieldName, "foo")))
+ )
+ );
+
+ // Multiple words - Keyword & text field
+ List.of(KEYWORD_FIELD_NAME, TEXT_FIELD_NAME)
+ .forEach(
+ fieldName -> assertThat(
+ parseKqlQuery(format("%s : { %s : %s }", NESTED_FIELD_NAME, fieldName, "foo bar")),
+ equalTo(parseKqlQuery(format("%s.%s : %s", NESTED_FIELD_NAME, fieldName, "foo bar")))
+ )
+ );
+
+ // Range syntax
+ {
+ String operator = randomFrom("<", "<=", ">", ">=");
+ double rangeValue = randomDouble();
+ assertThat(
+ parseKqlQuery(format("%s : { %s %s %s }", NESTED_FIELD_NAME, INT_FIELD_NAME, operator, rangeValue)),
+ equalTo(parseKqlQuery(format("%s.%s %s %s", NESTED_FIELD_NAME, INT_FIELD_NAME, operator, rangeValue)))
+ );
+ }
+
+ // Several level of nesting
+ {
+ QueryBuilder inlineQuery = parseKqlQuery(
+ format("%s.%s.%s : %s", NESTED_FIELD_NAME, NESTED_FIELD_NAME, TEXT_FIELD_NAME, "foo bar")
+ );
+
+ assertThat(
+ parseKqlQuery(format("%s : { %s : { %s : %s } }", NESTED_FIELD_NAME, NESTED_FIELD_NAME, TEXT_FIELD_NAME, "foo bar")),
+ equalTo(inlineQuery)
+ );
+
+ assertThat(
+ parseKqlQuery(format("%s.%s : { %s : %s }", NESTED_FIELD_NAME, NESTED_FIELD_NAME, TEXT_FIELD_NAME, "foo bar")),
+ equalTo(inlineQuery)
+ );
+
+ assertThat(
+ parseKqlQuery(format("%s : { %s.%s : %s }", NESTED_FIELD_NAME, NESTED_FIELD_NAME, TEXT_FIELD_NAME, "foo bar")),
+ equalTo(inlineQuery)
+ );
+ }
+ }
+
+ public void testBooleanAndNestedQuerySyntax() {
+ NestedQueryBuilder nestedQuery = asInstanceOf(
+ NestedQueryBuilder.class,
+ parseKqlQuery(
+ format("%s: { %s : foo AND %s: bar AND %s > 3}", NESTED_FIELD_NAME, TEXT_FIELD_NAME, KEYWORD_FIELD_NAME, INT_FIELD_NAME)
+ )
+ );
+ assertThat(nestedQuery.path(), equalTo(NESTED_FIELD_NAME));
+
+ BoolQueryBuilder subQuery = asInstanceOf(BoolQueryBuilder.class, nestedQuery.query());
+ assertThat(subQuery.should(), empty());
+ assertThat(subQuery.filter(), empty());
+ assertThat(subQuery.mustNot(), empty());
+ assertThat(subQuery.must(), hasSize(3));
+ assertMatchQueryBuilder(
+ subQuery.must().stream().filter(q -> q instanceof MatchQueryBuilder).findFirst().get(),
+ format("%s.%s", NESTED_FIELD_NAME, TEXT_FIELD_NAME),
+ "foo"
+ );
+ assertTermQueryBuilder(
+ subQuery.must().stream().filter(q -> q instanceof TermQueryBuilder).findFirst().get(),
+ format("%s.%s", NESTED_FIELD_NAME, KEYWORD_FIELD_NAME),
+ "bar"
+ );
+ assertRangeQueryBuilder(
+ subQuery.must().stream().filter(q -> q instanceof RangeQueryBuilder).findAny().get(),
+ format("%s.%s", NESTED_FIELD_NAME, INT_FIELD_NAME),
+ q -> {}
+ );
+ }
+
+ public void testBooleanOrNestedQuerySyntax() {
+ NestedQueryBuilder nestedQuery = asInstanceOf(
+ NestedQueryBuilder.class,
+ parseKqlQuery(
+ format("%s: { %s : foo OR %s: bar OR %s > 3 }", NESTED_FIELD_NAME, TEXT_FIELD_NAME, KEYWORD_FIELD_NAME, INT_FIELD_NAME)
+ )
+ );
+
+ assertThat(nestedQuery.path(), equalTo(NESTED_FIELD_NAME));
+
+ BoolQueryBuilder subQuery = asInstanceOf(BoolQueryBuilder.class, nestedQuery.query());
+ assertThat(subQuery.must(), empty());
+ assertThat(subQuery.filter(), empty());
+ assertThat(subQuery.mustNot(), empty());
+ assertThat(subQuery.should(), hasSize(3));
+ assertMatchQueryBuilder(
+ subQuery.should().stream().filter(q -> q instanceof MatchQueryBuilder).findFirst().get(),
+ format("%s.%s", NESTED_FIELD_NAME, TEXT_FIELD_NAME),
+ "foo"
+ );
+ assertTermQueryBuilder(
+ subQuery.should().stream().filter(q -> q instanceof TermQueryBuilder).findFirst().get(),
+ format("%s.%s", NESTED_FIELD_NAME, KEYWORD_FIELD_NAME),
+ "bar"
+ );
+ assertRangeQueryBuilder(
+ subQuery.should().stream().filter(q -> q instanceof RangeQueryBuilder).findAny().get(),
+ format("%s.%s", NESTED_FIELD_NAME, INT_FIELD_NAME),
+ q -> {}
+ );
+ }
+
+ public void testBooleanNotNestedQuerySyntax() {
+ {
+ NestedQueryBuilder nestedQuery = asInstanceOf(
+ NestedQueryBuilder.class,
+ parseKqlQuery(format("%s: { NOT %s : foo }", NESTED_FIELD_NAME, TEXT_FIELD_NAME))
+ );
+
+ assertThat(nestedQuery.path(), equalTo(NESTED_FIELD_NAME));
+
+ BoolQueryBuilder subQuery = asInstanceOf(BoolQueryBuilder.class, nestedQuery.query());
+ assertThat(subQuery.must(), empty());
+ assertThat(subQuery.filter(), empty());
+ assertThat(subQuery.should(), empty());
+ assertThat(subQuery.mustNot(), hasSize(1));
+ assertMatchQueryBuilder(subQuery.mustNot().get(0), format("%s.%s", NESTED_FIELD_NAME, TEXT_FIELD_NAME), "foo");
+ }
+
+ {
+ NestedQueryBuilder nestedQuery = asInstanceOf(
+ NestedQueryBuilder.class,
+ parseKqlQuery(format("%s: { NOT %s : foo }", NESTED_FIELD_NAME, KEYWORD_FIELD_NAME))
+ );
+
+ assertThat(nestedQuery.path(), equalTo(NESTED_FIELD_NAME));
+
+ BoolQueryBuilder subQuery = asInstanceOf(BoolQueryBuilder.class, nestedQuery.query());
+ assertThat(subQuery.must(), empty());
+ assertThat(subQuery.filter(), empty());
+ assertThat(subQuery.should(), empty());
+ assertThat(subQuery.mustNot(), hasSize(1));
+ assertTermQueryBuilder(subQuery.mustNot().get(0), format("%s.%s", NESTED_FIELD_NAME, KEYWORD_FIELD_NAME), "foo");
+ }
+
+ {
+ NestedQueryBuilder nestedQuery = asInstanceOf(
+ NestedQueryBuilder.class,
+ parseKqlQuery(format("%s: { NOT %s < 3 }", NESTED_FIELD_NAME, INT_FIELD_NAME))
+ );
+
+ assertThat(nestedQuery.path(), equalTo(NESTED_FIELD_NAME));
+
+ BoolQueryBuilder subQuery = asInstanceOf(BoolQueryBuilder.class, nestedQuery.query());
+ assertThat(subQuery.must(), empty());
+ assertThat(subQuery.filter(), empty());
+ assertThat(subQuery.should(), empty());
+ assertThat(subQuery.mustNot(), hasSize(1));
+ assertRangeQueryBuilder(subQuery.mustNot().get(0), format("%s.%s", NESTED_FIELD_NAME, INT_FIELD_NAME), q -> {});
+ }
+ }
+
+ private static String randomSearchTerms() {
+ return Stream.generate(ESTestCase::randomIdentifier).limit(randomIntBetween(1, 10)).collect(Collectors.joining(" "));
+ }
+}
diff --git a/x-pack/plugin/kql/src/test/java/org/elasticsearch/xpack/kql/parser/KqlParserExistsQueryTests.java b/x-pack/plugin/kql/src/test/java/org/elasticsearch/xpack/kql/parser/KqlParserExistsQueryTests.java
index 45dd3312bbc0..6415cdb94ada 100644
--- a/x-pack/plugin/kql/src/test/java/org/elasticsearch/xpack/kql/parser/KqlParserExistsQueryTests.java
+++ b/x-pack/plugin/kql/src/test/java/org/elasticsearch/xpack/kql/parser/KqlParserExistsQueryTests.java
@@ -10,7 +10,10 @@
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.ExistsQueryBuilder;
import org.elasticsearch.index.query.MatchNoneQueryBuilder;
-import org.elasticsearch.index.query.QueryBuilders;
+import org.elasticsearch.index.query.NestedQueryBuilder;
+import org.elasticsearch.index.query.QueryBuilder;
+
+import java.util.regex.Pattern;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.empty;
@@ -35,11 +38,18 @@ public void testParseExistsQueryWithNoMatchingFields() {
public void testParseExistsQueryWithASingleField() {
for (String fieldName : searchableFields()) {
- ExistsQueryBuilder parsedQuery = asInstanceOf(ExistsQueryBuilder.class, parseKqlQuery(kqlExistsQuery(fieldName)));
- assertThat(parsedQuery.fieldName(), equalTo(fieldName));
+ QueryBuilder parsedQuery = parseKqlQuery(kqlExistsQuery(fieldName));
// Using quotes to wrap the field name does not change the result.
assertThat(parseKqlQuery(kqlExistsQuery("\"" + fieldName + "\"")), equalTo(parsedQuery));
+
+ long nestingLevel = Pattern.compile("[.]").splitAsStream(fieldName).takeWhile(s -> s.equals(NESTED_FIELD_NAME)).count();
+ for (int i = 0; i < nestingLevel; i++) {
+ parsedQuery = asInstanceOf(NestedQueryBuilder.class, parsedQuery).query();
+ }
+
+ ExistsQueryBuilder existsQuery = asInstanceOf(ExistsQueryBuilder.class, parsedQuery);
+ assertThat(existsQuery.fieldName(), equalTo(fieldName));
}
}
@@ -53,7 +63,9 @@ public void testParseExistsQueryUsingWildcardFieldName() {
assertThat(
parsedQuery.should(),
- containsInAnyOrder(searchableFields(fieldNamePattern).stream().map(QueryBuilders::existsQuery).toArray())
+ containsInAnyOrder(
+ searchableFields(fieldNamePattern).stream().map(fieldName -> parseKqlQuery(kqlExistsQuery(fieldName))).toArray()
+ )
);
}
diff --git a/x-pack/plugin/kql/src/test/resources/supported-queries b/x-pack/plugin/kql/src/test/resources/supported-queries
index b659b1ae5b1d..f54a1d32fe3b 100644
--- a/x-pack/plugin/kql/src/test/resources/supported-queries
+++ b/x-pack/plugin/kql/src/test/resources/supported-queries
@@ -91,13 +91,6 @@ mapped_nested: { NOT(mapped_string:foo AND mapped_string_2:foo bar) }
mapped_nested: { NOT mapped_string:foo AND NOT mapped_string_2:foo bar }
mapped_nested: { (NOT mapped_string:foo) AND (NOT mapped_string_2:foo bar) }
mapped_nested: { NOT(mapped_string:foo) AND NOT(mapped_string_2:foo bar) }
-mapped_nested: { mapped_string:foo AND mapped_string_2:foo bar AND foo bar }
-mapped_nested: { mapped_string:foo AND mapped_string_2:foo bar OR foo bar }
-mapped_nested: { mapped_string:foo OR mapped_string_2:foo bar OR foo bar }
-mapped_nested: { mapped_string:foo OR mapped_string_2:foo bar AND foo bar }
-mapped_nested: { mapped_string:foo AND (mapped_string_2:foo bar OR foo bar) }
-mapped_nested: { mapped_string:foo AND (mapped_string_2:foo bar OR foo bar) }
-mapped_nested: { mapped_string:foo OR (mapped_string_2:foo bar OR foo bar) }
mapped_nested: { mapped_str*:foo }
mapped_nested: { mapped_nested : { mapped_string:foo AND mapped_int < 3 } AND mapped_string_2:foo bar }
mapped_nested: { mapped_nested.mapped_string:foo AND mapped_string_2:foo bar }
diff --git a/x-pack/plugin/kql/src/test/resources/unsupported-queries b/x-pack/plugin/kql/src/test/resources/unsupported-queries
index 149bcf5bd2b5..526ae94d6ac8 100644
--- a/x-pack/plugin/kql/src/test/resources/unsupported-queries
+++ b/x-pack/plugin/kql/src/test/resources/unsupported-queries
@@ -25,6 +25,20 @@ mapped_string:(foo (bar))
// Bad syntax for nested fields:
mapped_nested { mapped_string: bar }
+// Unknown nested field or not a nested field
+not_nested : { mapped_string: bar }
+mapped_string: { mapped_string: bar }
+
+// Nested query can not use fieldless subqueries
+mapped_nested: { foo }
+mapped_nested: { mapped_string:foo AND mapped_string_2:foo bar AND foo bar }
+mapped_nested: { mapped_string:foo AND mapped_string_2:foo bar OR foo bar }
+mapped_nested: { mapped_string:foo OR mapped_string_2:foo bar OR foo bar }
+mapped_nested: { mapped_string:foo OR mapped_string_2:foo bar AND foo bar }
+mapped_nested: { mapped_string:foo AND (mapped_string_2:foo bar OR foo bar) }
+mapped_nested: { mapped_string:foo AND (mapped_string_2:foo bar OR foo bar) }
+mapped_nested: { mapped_string:foo OR (mapped_string_2:foo bar OR foo bar) }
+
// Missing escape sequences:
mapped_string: foo:bar
mapped_string: (foo and bar)
diff --git a/x-pack/plugin/kql/src/yamlRestTest/resources/rest-api-spec/test/kql/50_kql_nested_fields_query.yml b/x-pack/plugin/kql/src/yamlRestTest/resources/rest-api-spec/test/kql/50_kql_nested_fields_query.yml
new file mode 100644
index 000000000000..4ce6688e5222
--- /dev/null
+++ b/x-pack/plugin/kql/src/yamlRestTest/resources/rest-api-spec/test/kql/50_kql_nested_fields_query.yml
@@ -0,0 +1,218 @@
+setup:
+ - requires:
+ capabilities:
+ - method: POST
+ path: /_search
+ capabilities: [ kql_query ]
+ test_runner_features: [ capabilities, contains ]
+ reason: KQL query is not available
+
+ - requires:
+ "test_runner_features": "contains"
+
+ - do:
+ indices.create:
+ index: test-index
+ body:
+ mappings:
+ properties:
+ department:
+ type: keyword
+ staff:
+ type: integer
+ courses:
+ type: nested
+ properties:
+ name:
+ type: text
+ credits:
+ type: integer
+ sessions:
+ type: nested
+ properties:
+ semester:
+ type: keyword
+ students:
+ type: integer
+
+ - do:
+ bulk:
+ index: test-index
+ refresh: true
+ body: |
+ { "index" : { "_id": "doc-1" } }
+ { "department": "compsci", "staff": 12, "courses": [ { "name": "Object Oriented Programming", "credits": 3, "sessions": [ { "semester": "spr2021", "students": 37 }, { "semester": "fall2020", "students": 45} ] }, { "name": "Theory of Computation", "credits": 4, "sessions": [ { "semester": "spr2021", "students": 19 }, { "semester": "fall2020", "students": 14 } ] } ] }
+ { "index" : { "_id": "doc-42" } }
+ { "department": "math", "staff": 20, "courses": [ { "name": "Precalculus", "credits": 1, "sessions": [ { "semester": "spr2021", "students": 100 }, { "semester": "fall2020", "students": 134 } ] }, { "name": "Linear Algebra", "credits": 3, "sessions": [ { "semester": "spr2021", "students": 29 }, { "semester": "fall2020", "students": 23 } ] } ] }
+
+---
+"Inline syntax":
+ - do:
+ search:
+ index: test-index
+ rest_total_hits_as_int: true
+ body: >
+ {
+ "query": {
+ "kql": {
+ "query": "courses.name: object oriented programming"
+ }
+ }
+ }
+ - match: { hits.total: 1 }
+ - match: { hits.hits.0._id: "doc-1" }
+
+ - do:
+ search:
+ index: test-index
+ rest_total_hits_as_int: true
+ body: >
+ {
+ "query": {
+ "kql": {
+ "query": "courses.name: object oriented programming AND courses.credits > 3"
+ }
+ }
+ }
+ - match: { hits.total: 1 }
+ - match: { hits.hits.0._id: "doc-1" }
+
+ - do:
+ search:
+ index: test-index
+ rest_total_hits_as_int: true
+ body: >
+ {
+ "query": {
+ "kql": {
+ "query": "courses.name: object oriented programming OR courses.credits > 3"
+ }
+ }
+ }
+ - match: { hits.total: 1 }
+ - match: { hits.hits.0._id: "doc-1" }
+
+
+---
+"Nested field syntax":
+ - do:
+ search:
+ index: test-index
+ rest_total_hits_as_int: true
+ body: >
+ {
+ "query": {
+ "kql": {
+ "query": "courses : { name: object oriented programming }"
+ }
+ }
+ }
+ - match: { hits.total: 1 }
+ - match: { hits.hits.0._id: "doc-1" }
+
+ - do:
+ search:
+ index: test-index
+ rest_total_hits_as_int: true
+ body: >
+ {
+ "query": {
+ "kql": {
+ "query": "courses: { name: object oriented programming AND credits > 3 }"
+ }
+ }
+ }
+ - match: { hits.total: 0 }
+
+ - do:
+ search:
+ index: test-index
+ rest_total_hits_as_int: true
+ body: >
+ {
+ "query": {
+ "kql": {
+ "query": "courses: { name: object oriented programming AND credits >= 3 }"
+ }
+ }
+ }
+ - match: { hits.total: 1 }
+ - match: { hits.hits.0._id: "doc-1" }
+
+ - do:
+ search:
+ index: test-index
+ rest_total_hits_as_int: true
+ body: >
+ {
+ "query": {
+ "kql": {
+ "query": "courses: { name: object oriented programming OR credits > 3 }"
+ }
+ }
+ }
+ - match: { hits.total: 1 }
+ - match: { hits.hits.0._id: "doc-1" }
+
+ - do:
+ search:
+ index: test-index
+ rest_total_hits_as_int: true
+ body: >
+ {
+ "query": {
+ "kql": {
+ "query": "courses: { NOT name: object oriented programming AND credits < 4 }"
+ }
+ }
+ }
+ - match: { hits.total: 1 }
+ - match: { hits.hits.0._id: "doc-42" }
+
+
+---
+"Several level of nesting field syntax":
+ - do:
+ search:
+ index: test-index
+ rest_total_hits_as_int: true
+ body: >
+ {
+ "query": {
+ "kql": {
+ "query": "courses: { name: object oriented programming AND sessions.semester: spr2021 }"
+ }
+ }
+ }
+ - match: { hits.total: 1 }
+ - match: { hits.hits.0._id: "doc-1" }
+
+ - do:
+ search:
+ index: test-index
+ rest_total_hits_as_int: true
+ body: >
+ {
+ "query": {
+ "kql": {
+ "query": "courses: { sessions : { semester: spr2021 AND students < 20 } }"
+ }
+ }
+ }
+ - match: { hits.total: 1 }
+ - match: { hits.hits.0._id: "doc-1" }
+
+ - do:
+ search:
+ index: test-index
+ rest_total_hits_as_int: true
+ body: >
+ {
+ "query": {
+ "kql": {
+ "query": "courses: { name: computation AND sessions : { semester: spr2021 AND students < 20 } }"
+ }
+ }
+ }
+ - match: { hits.total: 1 }
+ - match: { hits.hits.0._id: "doc-1" }