diff --git a/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/parser/AbstractBuilder.java b/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/parser/AbstractBuilder.java index 9da1e2fba8b5f..949fc077df78d 100644 --- a/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/parser/AbstractBuilder.java +++ b/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/parser/AbstractBuilder.java @@ -7,16 +7,11 @@ package org.elasticsearch.xpack.eql.parser; import org.antlr.v4.runtime.ParserRuleContext; -import org.antlr.v4.runtime.Token; -import org.antlr.v4.runtime.misc.Interval; import org.antlr.v4.runtime.tree.ParseTree; -import org.antlr.v4.runtime.tree.TerminalNode; +import org.elasticsearch.xpack.ql.parser.ParserUtils; import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; -import org.elasticsearch.xpack.ql.tree.Location; import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.util.Check; -import java.util.ArrayList; import java.util.List; /** @@ -26,21 +21,11 @@ abstract class AbstractBuilder extends EqlBaseBaseVisitor { @Override public Object visit(ParseTree tree) { - Object result = super.visit(tree); - Check.notNull(result, "Don't know how to handle context [{}] with value [{}]", tree.getClass(), tree.getText()); - return result; + return ParserUtils.visit(super::visit, tree); } - @SuppressWarnings("unchecked") protected T typedParsing(ParseTree ctx, Class type) { - Object result = ctx.accept(this); - if (type.isInstance(result)) { - return (T) result; - } - - throw new ParsingException(source(ctx), "Invalid query '{}'[{}] given; expected {} but found {}", - ctx.getText(), ctx.getClass().getSimpleName(), - type.getSimpleName(), (result != null ? result.getClass().getSimpleName() : "null")); + return ParserUtils.typedParsing(this, ctx, type); } protected LogicalPlan plan(ParseTree ctx) { @@ -48,68 +33,7 @@ protected LogicalPlan plan(ParseTree ctx) { } protected List plans(List ctxs) { - return visitList(ctxs, LogicalPlan.class); - } - - protected List visitList(List contexts, Class clazz) { - List results = new ArrayList<>(contexts.size()); - for (ParserRuleContext context : contexts) { - results.add(clazz.cast(visit(context))); - } - return results; - } - - static Source source(ParseTree ctx) { - if (ctx instanceof ParserRuleContext) { - return source((ParserRuleContext) ctx); - } - return Source.EMPTY; - } - - static Source source(TerminalNode terminalNode) { - Check.notNull(terminalNode, "terminalNode is null"); - return source(terminalNode.getSymbol()); - } - - static Source source(ParserRuleContext parserRuleContext) { - Check.notNull(parserRuleContext, "parserRuleContext is null"); - Token start = parserRuleContext.start; - Token stop = parserRuleContext.stop != null ? parserRuleContext.stop : start; - Interval interval = new Interval(start.getStartIndex(), stop.getStopIndex()); - String text = start.getInputStream().getText(interval); - return new Source(new Location(start.getLine(), start.getCharPositionInLine()), text); - } - - static Source source(Token token) { - Check.notNull(token, "token is null"); - String text = token.getInputStream().getText(new Interval(token.getStartIndex(), token.getStopIndex())); - return new Source(new Location(token.getLine(), token.getCharPositionInLine()), text); - } - - Source source(ParserRuleContext begin, ParserRuleContext end) { - Check.notNull(begin, "begin is null"); - Check.notNull(end, "end is null"); - Token start = begin.start; - Token stop = end.stop != null ? end.stop : begin.stop; - Interval interval = new Interval(start.getStartIndex(), stop.getStopIndex()); - String text = start.getInputStream().getText(interval); - return new Source(new Location(start.getLine(), start.getCharPositionInLine()), text); - } - - static Source source(TerminalNode begin, ParserRuleContext end) { - Check.notNull(begin, "begin is null"); - Check.notNull(end, "end is null"); - Token start = begin.getSymbol(); - Token stop = end.stop != null ? end.stop : start; - String text = start.getInputStream().getText(new Interval(start.getStartIndex(), stop.getStopIndex())); - return new Source(new Location(start.getLine(), start.getCharPositionInLine()), text); - } - - /** - * Retrieves the raw text of the node (without interpreting it as a string literal). - */ - static String text(ParseTree node) { - return node == null ? null : node.getText(); + return ParserUtils.visitList(this, ctxs, LogicalPlan.class); } public static String unquoteString(Source source) { @@ -212,11 +136,4 @@ private static void checkForSingleQuotedString(Source source, String text, int i "Use double quotes [\"] to define string literals, not single quotes [']"); } } - - @Override - public Object visitTerminal(TerminalNode node) { - Source source = source(node); - throw new ParsingException(source, "Does not know how to handle {}", source.text()); - } - } diff --git a/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/parser/ExpressionBuilder.java b/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/parser/ExpressionBuilder.java index de9bf2156158d..33e9423c256c7 100644 --- a/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/parser/ExpressionBuilder.java +++ b/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/parser/ExpressionBuilder.java @@ -58,6 +58,8 @@ import static java.util.Collections.emptyList; import static java.util.stream.Collectors.toList; +import static org.elasticsearch.xpack.ql.parser.ParserUtils.source; +import static org.elasticsearch.xpack.ql.parser.ParserUtils.visitList; public class ExpressionBuilder extends IdentifierBuilder { @@ -73,7 +75,7 @@ protected Expression expression(ParseTree ctx) { } protected List expressions(List contexts) { - return visitList(contexts, Expression.class); + return visitList(this, contexts, Expression.class); } @Override @@ -84,7 +86,7 @@ public Expression visitSingleExpression(EqlBaseParser.SingleExpressionContext ct @Override public List visitJoinKeys(JoinKeysContext ctx) { try { - return ctx != null ? visitList(ctx.expression(), Attribute.class) : emptyList(); + return ctx != null ? visitList(this, ctx.expression(), Attribute.class) : emptyList(); } catch (ClassCastException ex) { Source source = source(ctx); throw new ParsingException(source, "Unsupported join key ", source.text()); @@ -203,7 +205,7 @@ private Expression combineExpressions( List expressions, java.util.function.Function mapper ) { - return Predicates.combineOr(expressions(expressions).stream().map(mapper::apply).collect(toList())); + return Predicates.combineOr(expressions(expressions).stream().map(mapper).collect(toList())); } @Override diff --git a/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/parser/IdentifierBuilder.java b/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/parser/IdentifierBuilder.java index 348509578100e..b0f866faada73 100644 --- a/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/parser/IdentifierBuilder.java +++ b/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/parser/IdentifierBuilder.java @@ -10,6 +10,8 @@ import org.elasticsearch.xpack.eql.parser.EqlBaseParser.IdentifierContext; import org.elasticsearch.xpack.eql.parser.EqlBaseParser.QualifiedNameContext; +import static org.elasticsearch.xpack.ql.parser.ParserUtils.visitList; + abstract class IdentifierBuilder extends AbstractBuilder { @Override @@ -24,7 +26,7 @@ public String visitQualifiedName(QualifiedNameContext ctx) { } // this is fine, because we've already checked for array indexes [...] - return Strings.collectionToDelimitedString(visitList(ctx.identifier(), String.class), "."); + return Strings.collectionToDelimitedString(visitList(this, ctx.identifier(), String.class), "."); } private static String unquoteIdentifier(String identifier) { diff --git a/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/parser/LogicalPlanBuilder.java b/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/parser/LogicalPlanBuilder.java index d09798300808f..80eda6632adf9 100644 --- a/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/parser/LogicalPlanBuilder.java +++ b/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/parser/LogicalPlanBuilder.java @@ -56,6 +56,8 @@ import static java.util.Collections.emptyList; import static java.util.Collections.singletonList; +import static org.elasticsearch.xpack.ql.parser.ParserUtils.source; +import static org.elasticsearch.xpack.ql.parser.ParserUtils.text; import static org.elasticsearch.xpack.ql.tree.Source.synthetic; public abstract class LogicalPlanBuilder extends ExpressionBuilder { diff --git a/x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/parser/CaseChangingCharStream.java b/x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/parser/CaseChangingCharStream.java new file mode 100644 index 0000000000000..58c2cd24c3363 --- /dev/null +++ b/x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/parser/CaseChangingCharStream.java @@ -0,0 +1,92 @@ +/* + * 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.ql.parser; + +import org.antlr.v4.runtime.CharStream; +import org.antlr.v4.runtime.misc.Interval; + +// Wrapping stream for handling case-insensitive grammars + +// This approach is taken from the ANTLR documentation +// https://github.com/antlr/antlr4/blob/master/doc/resources/CaseChangingCharStream.java +// https://github.com/antlr/antlr4/blob/master/doc/case-insensitive-lexing.md + +/** + * This class supports case-insensitive lexing by wrapping an existing + * {@link CharStream} and forcing the lexer to see either upper or + * lowercase characters. Grammar literals should then be either upper or + * lower case such as 'BEGIN' or 'begin'. The text of the character + * stream is unaffected. Example: input 'BeGiN' would match lexer rule + * 'BEGIN' if constructor parameter upper=true but getText() would return + * 'BeGiN'. + */ +public class CaseChangingCharStream implements CharStream { + + private final CharStream stream; + private final boolean upper; + + /** + * Constructs a new CaseChangingCharStream wrapping the given {@link CharStream} forcing + * all characters to upper case or lower case. + * @param stream The stream to wrap. + * @param upper If true force each symbol to upper case, otherwise force to lower. + */ + public CaseChangingCharStream(CharStream stream, boolean upper) { + this.stream = stream; + this.upper = upper; + } + + @Override + public String getText(Interval interval) { + return stream.getText(interval); + } + + @Override + public void consume() { + stream.consume(); + } + + @Override + public int LA(int i) { + int c = stream.LA(i); + if (c <= 0) { + return c; + } + return upper ? Character.toUpperCase(c) : Character.toLowerCase(c); + } + + @Override + public int mark() { + return stream.mark(); + } + + @Override + public void release(int marker) { + stream.release(marker); + } + + @Override + public int index() { + return stream.index(); + } + + @Override + public void seek(int index) { + stream.seek(index); + } + + @Override + public int size() { + return stream.size(); + } + + @Override + public String getSourceName() { + return stream.getSourceName(); + } +} diff --git a/x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/parser/ParserUtils.java b/x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/parser/ParserUtils.java new file mode 100644 index 0000000000000..d7ed927394500 --- /dev/null +++ b/x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/parser/ParserUtils.java @@ -0,0 +1,120 @@ +/* + * 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.ql.parser; + +import org.antlr.v4.runtime.ParserRuleContext; +import org.antlr.v4.runtime.Token; +import org.antlr.v4.runtime.misc.Interval; +import org.antlr.v4.runtime.tree.ParseTree; +import org.antlr.v4.runtime.tree.ParseTreeVisitor; +import org.antlr.v4.runtime.tree.TerminalNode; +import org.elasticsearch.xpack.ql.ParsingException; +import org.elasticsearch.xpack.ql.tree.Location; +import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.ql.util.Check; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Function; + +import static java.util.Collections.emptyList; + +public final class ParserUtils { + + private ParserUtils() {} + + public static Object visit(Function visitor, ParseTree tree) { + Object result = visitor.apply(tree); + Check.notNull(result, "Don't know how to handle context [{}] with value [{}]", tree.getClass(), tree.getText()); + return result; + } + + public static List visitList(ParseTreeVisitor visitor, List contexts, Class clazz) { + if (contexts == null || contexts.isEmpty()) { + return emptyList(); + } + + List results = new ArrayList<>(contexts.size()); + for (ParserRuleContext context : contexts) { + results.add(clazz.cast(visitor.visit(context))); + } + return results; + } + + @SuppressWarnings("unchecked") + public static T typedParsing(ParseTreeVisitor visitor, ParseTree ctx, Class type) { + Object result = ctx.accept(visitor); + if (type.isInstance(result)) { + return (T) result; + } + + throw new ParsingException( + source(ctx), + "Invalid query '{}'[{}] given; expected {} but found {}", + ctx.getText(), + ctx.getClass().getSimpleName(), + type.getSimpleName(), + (result != null ? result.getClass().getSimpleName() : "null") + ); + } + + public static Source source(ParseTree ctx) { + if (ctx instanceof ParserRuleContext) { + return source((ParserRuleContext) ctx); + } + return Source.EMPTY; + } + + public static Source source(TerminalNode terminalNode) { + Check.notNull(terminalNode, "terminalNode is null"); + return source(terminalNode.getSymbol()); + } + + public static Source source(ParserRuleContext parserRuleContext) { + Check.notNull(parserRuleContext, "parserRuleContext is null"); + Token start = parserRuleContext.start; + Token stop = parserRuleContext.stop != null ? parserRuleContext.stop : start; + return source(start, stop); + } + + public static Source source(Token token) { + Check.notNull(token, "token is null"); + String text = token.getInputStream().getText(new Interval(token.getStartIndex(), token.getStopIndex())); + return new Source(new Location(token.getLine(), token.getCharPositionInLine()), text); + } + + public static Source source(ParserRuleContext begin, ParserRuleContext end) { + Check.notNull(begin, "begin is null"); + Check.notNull(end, "end is null"); + Token start = begin.start; + Token stop = end.stop != null ? end.stop : begin.stop; + return source(start, stop); + } + + public static Source source(TerminalNode begin, ParserRuleContext end) { + Check.notNull(begin, "begin is null"); + Check.notNull(end, "end is null"); + Token start = begin.getSymbol(); + Token stop = end.stop != null ? end.stop : start; + return source(start, stop); + } + + public static Source source(Token start, Token stop) { + Check.notNull(start, "start is null"); + stop = stop == null ? start : stop; + String text = start.getInputStream().getText(new Interval(start.getStartIndex(), stop.getStopIndex())); + return new Source(new Location(start.getLine(), start.getCharPositionInLine()), text); + } + + /** + * Retrieves the raw text of the node (without interpreting it as a string literal). + */ + public static String text(ParseTree node) { + return node == null ? null : node.getText(); + } +} diff --git a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/parser/AbstractBuilder.java b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/parser/AbstractBuilder.java index 4470e8f24a297..027760fdf238b 100644 --- a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/parser/AbstractBuilder.java +++ b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/parser/AbstractBuilder.java @@ -7,16 +7,11 @@ package org.elasticsearch.xpack.sql.parser; import org.antlr.v4.runtime.ParserRuleContext; -import org.antlr.v4.runtime.Token; -import org.antlr.v4.runtime.misc.Interval; import org.antlr.v4.runtime.tree.ParseTree; import org.antlr.v4.runtime.tree.TerminalNode; +import org.elasticsearch.xpack.ql.parser.ParserUtils; import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; -import org.elasticsearch.xpack.ql.tree.Location; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.sql.util.Check; -import java.util.ArrayList; import java.util.List; /** @@ -33,21 +28,11 @@ abstract class AbstractBuilder extends SqlBaseBaseVisitor { @Override public Object visit(ParseTree tree) { - Object result = super.visit(tree); - Check.notNull(result, "Don't know how to handle context [{}] with value [{}]", tree.getClass(), tree.getText()); - return result; + return ParserUtils.visit(super::visit, tree); } - @SuppressWarnings("unchecked") protected T typedParsing(ParseTree ctx, Class type) { - Object result = ctx.accept(this); - if (type.isInstance(result)) { - return (T) result; - } - - throw new ParsingException(source(ctx), "Invalid query '{}'[{}] given; expected {} but found {}", - ctx.getText(), ctx.getClass().getSimpleName(), - type.getSimpleName(), (result != null ? result.getClass().getSimpleName() : "null")); + return ParserUtils.typedParsing(this, ctx, type); } protected LogicalPlan plan(ParseTree ctx) { @@ -55,68 +40,7 @@ protected LogicalPlan plan(ParseTree ctx) { } protected List plans(List ctxs) { - return visitList(ctxs, LogicalPlan.class); - } - - protected List visitList(List contexts, Class clazz) { - List results = new ArrayList<>(contexts.size()); - for (ParserRuleContext context : contexts) { - results.add(clazz.cast(visit(context))); - } - return results; - } - - static Source source(ParseTree ctx) { - if (ctx instanceof ParserRuleContext) { - return source((ParserRuleContext) ctx); - } - return Source.EMPTY; - } - - static Source source(TerminalNode terminalNode) { - Check.notNull(terminalNode, "terminalNode is null"); - return source(terminalNode.getSymbol()); - } - - static Source source(ParserRuleContext parserRuleContext) { - Check.notNull(parserRuleContext, "parserRuleContext is null"); - Token start = parserRuleContext.start; - Token stop = parserRuleContext.stop != null ? parserRuleContext.stop : start; - Interval interval = new Interval(start.getStartIndex(), stop.getStopIndex()); - String text = start.getInputStream().getText(interval); - return new Source(new Location(start.getLine(), start.getCharPositionInLine()), text); - } - - static Source source(Token token) { - Check.notNull(token, "token is null"); - String text = token.getInputStream().getText(new Interval(token.getStartIndex(), token.getStopIndex())); - return new Source(new Location(token.getLine(), token.getCharPositionInLine()), text); - } - - Source source(ParserRuleContext begin, ParserRuleContext end) { - Check.notNull(begin, "begin is null"); - Check.notNull(end, "end is null"); - Token start = begin.start; - Token stop = end.stop != null ? end.stop : begin.stop; - Interval interval = new Interval(start.getStartIndex(), stop.getStopIndex()); - String text = start.getInputStream().getText(interval); - return new Source(new Location(start.getLine(), start.getCharPositionInLine()), text); - } - - static Source source(TerminalNode begin, ParserRuleContext end) { - Check.notNull(begin, "begin is null"); - Check.notNull(end, "end is null"); - Token start = begin.getSymbol(); - Token stop = end.stop != null ? end.stop : start; - String text = start.getInputStream().getText(new Interval(start.getStartIndex(), stop.getStopIndex())); - return new Source(new Location(start.getLine(), start.getCharPositionInLine()), text); - } - - /** - * Retrieves the raw text of the node (without interpreting it as a string literal). - */ - static String text(ParseTree node) { - return node == null ? null : node.getText(); + return ParserUtils.visitList(this, ctxs, LogicalPlan.class); } /** @@ -133,7 +57,6 @@ static String unquoteString(String text) { @Override public Object visitTerminal(TerminalNode node) { - Source source = source(node); - throw new ParsingException(source, "Does not know how to handle {}", source.text()); + return ParserUtils.source(node); } } diff --git a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/parser/CaseInsensitiveStream.java b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/parser/CaseInsensitiveStream.java deleted file mode 100644 index bbb88f7e5cfa1..0000000000000 --- a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/parser/CaseInsensitiveStream.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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.sql.parser; - -import org.antlr.v4.runtime.ANTLRInputStream; -import org.antlr.v4.runtime.IntStream; - -import java.util.Locale; - -// extension of ANTLR that does the upper-casing once for the whole stream -// the ugly part is that it has to duplicate LA method - -// This approach is the official solution from the ANTLR authors -// in that it's both faster and easier than having a dedicated lexer -// see https://github.com/antlr/antlr4/issues/1002 -class CaseInsensitiveStream extends ANTLRInputStream { - protected char[] uppedChars; - - CaseInsensitiveStream(String input) { - super(input); - this.uppedChars = input.toUpperCase(Locale.ROOT).toCharArray(); - } - - // this part is copied from ANTLRInputStream - @Override - public int LA(int i) { - if (i == 0) { - return 0; // undefined - } - if (i < 0) { - i++; - if ((p + i - 1) < 0) { - return IntStream.EOF; - } - } - - if ((p + i - 1) >= n) { - return IntStream.EOF; - } - return uppedChars[p + i - 1]; - } -} diff --git a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/parser/CommandBuilder.java b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/parser/CommandBuilder.java index 7ecfff4040ddb..e4e81cdcfb381 100644 --- a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/parser/CommandBuilder.java +++ b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/parser/CommandBuilder.java @@ -44,6 +44,8 @@ import java.util.Locale; import java.util.Map; +import static org.elasticsearch.xpack.ql.parser.ParserUtils.source; + abstract class CommandBuilder extends LogicalPlanBuilder { protected CommandBuilder(Map params, ZoneId zoneId) { @@ -115,7 +117,7 @@ public Command visitExplain(ExplainContext ctx) { } boolean graphViz = ctx.format != null && ctx.format.getType() == SqlBaseLexer.GRAPHVIZ; Explain.Format format = graphViz ? Explain.Format.GRAPHVIZ : Explain.Format.TEXT; - boolean verify = (ctx.verify != null ? Booleans.parseBoolean(ctx.verify.getText().toLowerCase(Locale.ROOT), true) : true); + boolean verify = (ctx.verify == null || Booleans.parseBoolean(ctx.verify.getText().toLowerCase(Locale.ROOT), true)); return new Explain(source, plan(ctx.statement()), type, format, verify); } diff --git a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/parser/ExpressionBuilder.java b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/parser/ExpressionBuilder.java index 288368202baac..f51284fac50cc 100644 --- a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/parser/ExpressionBuilder.java +++ b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/parser/ExpressionBuilder.java @@ -134,6 +134,9 @@ import static java.util.Collections.emptyList; import static java.util.Collections.singletonList; +import static org.elasticsearch.xpack.ql.parser.ParserUtils.source; +import static org.elasticsearch.xpack.ql.parser.ParserUtils.text; +import static org.elasticsearch.xpack.ql.parser.ParserUtils.visitList; import static org.elasticsearch.xpack.sql.type.SqlDataTypeConverter.canConvert; import static org.elasticsearch.xpack.sql.type.SqlDataTypeConverter.converterFor; import static org.elasticsearch.xpack.sql.util.DateUtils.asDateOnly; @@ -155,7 +158,7 @@ protected Expression expression(ParseTree ctx) { } protected List expressions(List contexts) { - return visitList(contexts, Expression.class); + return visitList(this, contexts, Expression.class); } @Override diff --git a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/parser/IdentifierBuilder.java b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/parser/IdentifierBuilder.java index 14ae8457cf693..bcb69ac06fb9d 100644 --- a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/parser/IdentifierBuilder.java +++ b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/parser/IdentifierBuilder.java @@ -14,6 +14,9 @@ import org.elasticsearch.xpack.sql.parser.SqlBaseParser.QualifiedNameContext; import org.elasticsearch.xpack.sql.parser.SqlBaseParser.TableIdentifierContext; +import static org.elasticsearch.xpack.ql.parser.ParserUtils.source; +import static org.elasticsearch.xpack.ql.parser.ParserUtils.visitList; + abstract class IdentifierBuilder extends AbstractBuilder { @Override @@ -40,7 +43,7 @@ public String visitQualifiedName(QualifiedNameContext ctx) { return null; } - return Strings.collectionToDelimitedString(visitList(ctx.identifier(), String.class), "."); + return Strings.collectionToDelimitedString(visitList(this, ctx.identifier(), String.class), "."); } private static String unquoteIdentifier(String identifier) { diff --git a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/parser/LogicalPlanBuilder.java b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/parser/LogicalPlanBuilder.java index 5ed7085b9dbea..7d1be389807a9 100644 --- a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/parser/LogicalPlanBuilder.java +++ b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/parser/LogicalPlanBuilder.java @@ -63,6 +63,8 @@ import java.util.Map; import static java.util.Collections.emptyList; +import static org.elasticsearch.xpack.ql.parser.ParserUtils.source; +import static org.elasticsearch.xpack.ql.parser.ParserUtils.visitList; abstract class LogicalPlanBuilder extends ExpressionBuilder { @@ -74,7 +76,7 @@ protected LogicalPlanBuilder(Map params, ZoneId zoneI public LogicalPlan visitQuery(QueryContext ctx) { LogicalPlan body = plan(ctx.queryNoWith()); - List namedQueries = visitList(ctx.namedQuery(), SubQueryAlias.class); + List namedQueries = visitList(this, ctx.namedQuery(), SubQueryAlias.class); // unwrap query (and validate while at it) Map cteRelations = new LinkedHashMap<>(namedQueries.size()); @@ -101,7 +103,7 @@ public LogicalPlan visitQueryNoWith(QueryNoWithContext ctx) { List orders = ctx.orderBy(); OrderByContext endContext = orders.get(orders.size() - 1); Source source = source(ctx.ORDER(), endContext); - List order = visitList(ctx.orderBy(), Order.class); + List order = visitList(this, ctx.orderBy(), Order.class); if (plan instanceof Limit) { // Limit from TOP clauses must be the parent of the OrderBy clause @@ -142,8 +144,9 @@ public LogicalPlan visitQuerySpecification(QuerySpecificationContext ctx) { query = new Filter(source(ctx), query, expression(ctx.where)); } - List selectTarget = ctx.selectItems().isEmpty() ? emptyList() : visitList(ctx.selectItems().selectItem(), - NamedExpression.class); + List selectTarget = ctx.selectItems().isEmpty() + ? emptyList() + : visitList(this, ctx.selectItems().selectItem(), NamedExpression.class); // GROUP BY GroupByContext groupByCtx = ctx.groupBy(); diff --git a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/parser/SqlParser.java b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/parser/SqlParser.java index 85d6126797619..ac6ae1a02a323 100644 --- a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/parser/SqlParser.java +++ b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/parser/SqlParser.java @@ -8,6 +8,7 @@ import org.antlr.v4.runtime.BaseErrorListener; import org.antlr.v4.runtime.CharStream; +import org.antlr.v4.runtime.CharStreams; import org.antlr.v4.runtime.CommonToken; import org.antlr.v4.runtime.CommonTokenStream; import org.antlr.v4.runtime.DiagnosticErrorListener; @@ -26,6 +27,7 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.elasticsearch.xpack.ql.expression.Expression; +import org.elasticsearch.xpack.ql.parser.CaseChangingCharStream; import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; import org.elasticsearch.xpack.sql.proto.SqlTypedParamValue; @@ -100,7 +102,7 @@ private T invokeParser(String sql, Function parseFunction, BiFunction visitor) { try { - SqlBaseLexer lexer = new SqlBaseLexer(new CaseInsensitiveStream(sql)); + SqlBaseLexer lexer = new SqlBaseLexer(new CaseChangingCharStream(CharStreams.fromString(sql), true)); lexer.removeErrorListeners(); lexer.addErrorListener(ERROR_LISTENER);