diff --git a/common/build.gradle b/common/build.gradle index 7b0554c308..9013a72ee8 100644 --- a/common/build.gradle +++ b/common/build.gradle @@ -9,6 +9,7 @@ repositories { dependencies { compile "org.antlr:antlr4-runtime:4.7.1" + compile group: 'com.google.guava', name: 'guava', version:'15.0' testCompile group: 'junit', name: 'junit', version: '4.12' } diff --git a/common/src/main/java/com/amazon/opendistroforelasticsearch/sql/common/utils/StringUtils.java b/common/src/main/java/com/amazon/opendistroforelasticsearch/sql/common/utils/StringUtils.java new file mode 100644 index 0000000000..75d590878e --- /dev/null +++ b/common/src/main/java/com/amazon/opendistroforelasticsearch/sql/common/utils/StringUtils.java @@ -0,0 +1,44 @@ +/* + * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.amazon.opendistroforelasticsearch.sql.common.utils; + +import com.google.common.base.Strings; + +public class StringUtils { + /** + * @param text string + * @param mark quotation mark + * @return An unquoted string whose outer pair of (single/double/back-tick) quotes have been removed + */ + public static String unquoteIdentifier(String text, String mark) { + if (isQuoted(text, mark)) { + return text.substring(mark.length(), text.length() - mark.length()); + } + return text; + } + + public static String unquoteIdentifier(String text) { + if (isQuoted(text, "\"") || isQuoted(text, "'") || isQuoted(text, "`")) { + return text.substring(1, text.length() - 1); + } else { + return text; + } + } + + private static boolean isQuoted(String text, String mark) { + return !Strings.isNullOrEmpty(text) && text.startsWith(mark) && text.endsWith(mark); + } +} diff --git a/ppl/build.gradle b/ppl/build.gradle index 28056ae1f1..1ec0d2bf54 100644 --- a/ppl/build.gradle +++ b/ppl/build.gradle @@ -25,6 +25,8 @@ dependencies { antlr "org.antlr:antlr4:4.7.1" compile "org.antlr:antlr4-runtime:4.7.1" + compile group: 'com.google.guava', name: 'guava', version:'15.0' + compile group: 'org.elasticsearch', name: 'elasticsearch-x-content', version:"${es_version}" compile group: 'org.json', name: 'json', version:'20180813' compile group: 'org.springframework', name: 'spring-context', version: '5.2.5.RELEASE' compile group: 'org.springframework', name: 'spring-beans', version: '5.2.5.RELEASE' diff --git a/ppl/src/main/antlr/OpenDistroPPLLexer.g4 b/ppl/src/main/antlr/OpenDistroPPLLexer.g4 index d3db17281d..7af6c132fa 100644 --- a/ppl/src/main/antlr/OpenDistroPPLLexer.g4 +++ b/ppl/src/main/antlr/OpenDistroPPLLexer.g4 @@ -90,6 +90,11 @@ EXCLAMATION_SYMBOL: '!'; COLON: ':'; LT_PRTHS: '('; RT_PRTHS: ')'; +LT_SQR_PRTHS: '['; +RT_SQR_PRTHS: ']'; +SINGLE_QUOTE: '\''; +DOUBLE_QUOTE: '"'; +BACKTICK: '`'; // AGGREGATIONS AVG: 'AVG'; @@ -240,16 +245,15 @@ WILDCARDQUERY: 'WILDCARDQUERY'; WILDCARD_QUERY: 'WILDCARD_QUERY'; // LITERALS AND VALUES -STRING_LITERAL: DQUOTA_STRING | SQUOTA_STRING | BQUOTA_STRING; +//STRING_LITERAL: DQUOTA_STRING | SQUOTA_STRING | BQUOTA_STRING; ID: ID_LITERAL; -DOT_ID: '.' ID; -DECIMAL_LITERAL: DEC_DIGIT+; -// TODO: define WCFIELD +INTEGER_LITERAL: DEC_DIGIT+; +DECIMAL_LITERAL: (DEC_DIGIT+)? '.' DEC_DIGIT+; fragment ID_LITERAL: [A-Z_$0-9@]*?[A-Z_$\-]+?[A-Z_$\-0-9]*; -fragment DQUOTA_STRING: '"' ( '\\'. | '""' | ~('"'| '\\') )* '"'; -fragment SQUOTA_STRING: '\'' ('\\'. | '\'\'' | ~('\'' | '\\'))* '\''; -fragment BQUOTA_STRING: '`' ( '\\'. | '``' | ~('`'|'\\'))* '`'; +DQUOTA_STRING: '"' ( '\\'. | '""' | ~('"'| '\\') )* '"'; +SQUOTA_STRING: '\'' ('\\'. | '\'\'' | ~('\'' | '\\'))* '\''; +BQUOTA_STRING: '`' ( '\\'. | '``' | ~('`'|'\\'))* '`'; fragment DEC_DIGIT: [0-9]; diff --git a/ppl/src/main/antlr/OpenDistroPPLParser.g4 b/ppl/src/main/antlr/OpenDistroPPLParser.g4 index 300e71b515..446465835b 100644 --- a/ppl/src/main/antlr/OpenDistroPPLParser.g4 +++ b/ppl/src/main/antlr/OpenDistroPPLParser.g4 @@ -26,32 +26,31 @@ pplStatement : searchCommand (PIPE commands)* ; - /** commands */ commands : whereCommand | fieldsCommand | renameCommand | statsCommand | dedupCommand | sortCommand | evalCommand ; searchCommand - : (SEARCH)? fromClause #searchWithoutFilter - | (SEARCH)? fromClause logicalExpression #searchFromClauseLogicExpr - | (SEARCH)? logicalExpression fromClause #searchLogicExprFromClause + : (SEARCH)? fromClause #searchFrom + | (SEARCH)? fromClause logicalExpression #searchFromFilter + | (SEARCH)? logicalExpression fromClause #searchFilterFrom ; whereCommand - : WHERE evalExpression + : WHERE logicalExpression ; fieldsCommand - : FIELDS fieldList + : FIELDS (PLUS | MINUS)? wcFieldList ; renameCommand - : RENAME wcField AS wcField + : RENAME orignalField=wcFieldExpression AS renamedField=wcFieldExpression ; statsCommand - : STATS (statsArgument)* (statsAggTerm | sparklineAggTerm) (byClause)? (dedupSplitValues)? + : STATS (statsArgument)* statsAggTerm (byClause)? (dedupSplitValues)? ; dedupCommand @@ -63,7 +62,7 @@ sortCommand ; evalCommand - : EVAL fieldExpression EQUAL evalExpression (COMMA fieldExpression EQUAL evalExpression) + : EVAL evalExpression (COMMA evalExpression)* ; /** arguments */ @@ -94,16 +93,12 @@ byClause ; sortbyClause - : (PLUS | MINUS) sortField (COMMA (PLUS | MINUS) sortField)* + : (PLUS | MINUS)? sortField (COMMA (PLUS | MINUS)? sortField)* ; /** aggregation terms */ -aggregationTerm - : statsAggTerm | sparklineAggTerm - ; - statsAggTerm - : statsFunction LT_PRTHS (fieldExpression)? RT_PRTHS + : statsFunction ; sparklineAggTerm @@ -116,8 +111,8 @@ statsFunction ; aggregationFunction - : aggFunctionName LT_PRTHS fieldExpression RT_PRTHS - | percentileAggFunction + : aggFunctionName LT_PRTHS fieldExpression RT_PRTHS #aggFunctionCall + | percentileAggFunction #percentileAggFunctionCall ; aggFunctionName @@ -126,7 +121,7 @@ aggFunctionName ; percentileAggFunction - : PERCENTILE LESS fieldExpression GREATER LT_PRTHS fieldExpression RT_PRTHS + : PERCENTILE LESS value=decimalLiteral GREATER LT_PRTHS aggField=fieldExpression RT_PRTHS ; eventOrderFunction @@ -148,8 +143,8 @@ timeFunctionName ; sparklineAggregation - : SPARKLINE LT_PRTHS COUNT LT_PRTHS wcField RT_PRTHS COMMA spanLength=decimalLiteral RT_PRTHS - | SPARKLINE RT_PRTHS sparklineFunction LT_PRTHS wcField RT_PRTHS COMMA spanLength=decimalLiteral RT_PRTHS + : SPARKLINE LT_PRTHS COUNT LT_PRTHS wcFieldExpression RT_PRTHS COMMA spanLength=decimalLiteral RT_PRTHS + | SPARKLINE RT_PRTHS sparklineFunction LT_PRTHS wcFieldExpression RT_PRTHS COMMA spanLength=decimalLiteral RT_PRTHS ; sparklineFunction @@ -157,7 +152,8 @@ sparklineFunction ; sparklineFunctionName - : C | COUNT | DC | MEAN | AVG | STDEV | STDEVP | VAR | VARP | SUM | SUMSQ | MIN | MAX | RANGE + : +// | C | COUNT | DC | MEAN | AVG | STDEV | STDEVP | VAR | VARP | SUM | SUMSQ | MIN | MAX | RANGE ; /** expressions */ @@ -173,28 +169,28 @@ logicalExpression | comparisonExpression #comparsion | evalExpression #eval | NOT logicalExpression #logicalNot - | left=logicalExpression OR right=logicalExpression #logicalOrBinary - | left=logicalExpression (AND)? right=logicalExpression #logicalAndBinary + | left=logicalExpression OR right=logicalExpression #logicalOr + | left=logicalExpression (AND)? right=logicalExpression #logicalAnd ; evalExpression - : literalValue EQUAL literalValue - | evalFunctionCall + : fieldExpression EQUAL evalFunctionCall ; comparisonExpression - : left=fieldExpression comparisonOperator right=literalValue - | fieldExpression IN valueList + : left=fieldExpression comparisonOperator right=literalValue #compareExpr + | fieldExpression IN valueList #inExpr ; booleanExpression - : LT_PRTHS booleanExpression RT_PRTHS + : LT_PRTHS booleanLiteral RT_PRTHS | booleanLiteral ; /** tables */ tableSource : ident + | stringLiteral ; /** fields */ @@ -202,6 +198,10 @@ fieldList : fieldExpression (COMMA fieldExpression)* ; +wcFieldList + : wcFieldExpression (COMMA wcFieldExpression)* + ; + sortField : fieldExpression #defaultSort | AUTO LT_PRTHS fieldExpression RT_PRTHS #autoSort @@ -210,14 +210,18 @@ sortField | NUM LT_PRTHS fieldExpression RT_PRTHS #numSort ; -wcField - : WCFIELD - ; - fieldExpression : ident + | SINGLE_QUOTE ident SINGLE_QUOTE + | DOUBLE_QUOTE ident DOUBLE_QUOTE + | BACKTICK ident BACKTICK + ; + +wcFieldExpression + : wildcard ; + /** functions */ evalFunctionCall : evalFunctionName LT_PRTHS functionArgs RT_PRTHS @@ -253,7 +257,7 @@ functionArgs ; functionArg - : constant | fullColumnName | expression | evalFunctionCall + : expression | fieldExpression | literalValue ; /** operators */ @@ -264,11 +268,17 @@ comparisonOperator /** literals and values*/ literalValue : stringLiteral - | decimalLiteral + | (PLUS | MINUS)? integerLiteral + | (PLUS | MINUS)? decimalLiteral + | booleanLiteral ; stringLiteral - : STRING_LITERAL + : DQUOTA_STRING | SQUOTA_STRING | BQUOTA_STRING + ; + +integerLiteral + : INTEGER_LITERAL ; decimalLiteral @@ -283,32 +293,10 @@ valueList : LT_PRTHS literalValue (COMMA literalValue)* RT_PRTHS ; -fullColumnName - : simpleId DOT_ID* - ; - -constant - : stringLiteral | decimalLiteral - | MINUS decimalLiteral - | booleanLiteral - ; - -simpleId - : ID - | DOT_ID - | STRING_LITERAL - ; - ident - : ID - | DOT_ID + : (DOT)? ID ; -/** dataset */ -datasetType - : DATAMODEL | LOOKUP | SAVEDSEARCH - ; - -datasetName - : +wildcard + : (MODULE | ident)+ ; diff --git a/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/antlr/PPLSyntaxParser.java b/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/antlr/PPLSyntaxParser.java index 10ee4e2461..36019a8d5c 100644 --- a/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/antlr/PPLSyntaxParser.java +++ b/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/antlr/PPLSyntaxParser.java @@ -27,8 +27,8 @@ * PPL Syntax Parser */ public class PPLSyntaxParser { - public ParseTree analyzeSyntax(String sql) { - OpenDistroPPLParser parser = createParser(createLexer(sql)); + public ParseTree analyzeSyntax(String query) { + OpenDistroPPLParser parser = createParser(createLexer(query)); parser.addErrorListener(new SyntaxAnalysisErrorListener()); return parser.root(); } @@ -38,8 +38,8 @@ private OpenDistroPPLParser createParser(Lexer lexer) { new CommonTokenStream(lexer)); } - private OpenDistroPPLLexer createLexer(String sql) { + private OpenDistroPPLLexer createLexer(String query) { return new OpenDistroPPLLexer( - new CaseInsensitiveCharStream(sql)); + new CaseInsensitiveCharStream(query)); } } diff --git a/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/node/AbstractNodeVisitor.java b/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/node/AbstractNodeVisitor.java new file mode 100644 index 0000000000..9d9c141a72 --- /dev/null +++ b/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/node/AbstractNodeVisitor.java @@ -0,0 +1,123 @@ +/* + * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.amazon.opendistroforelasticsearch.sql.ppl.node; + +import com.amazon.opendistroforelasticsearch.sql.ppl.plans.expression.AggregateFunction; +import com.amazon.opendistroforelasticsearch.sql.ppl.plans.expression.And; +import com.amazon.opendistroforelasticsearch.sql.ppl.plans.expression.AttributeList; +import com.amazon.opendistroforelasticsearch.sql.ppl.plans.expression.EqualTo; +import com.amazon.opendistroforelasticsearch.sql.ppl.plans.expression.Function; +import com.amazon.opendistroforelasticsearch.sql.ppl.plans.expression.In; +import com.amazon.opendistroforelasticsearch.sql.ppl.plans.expression.Literal; +import com.amazon.opendistroforelasticsearch.sql.ppl.plans.expression.Map; +import com.amazon.opendistroforelasticsearch.sql.ppl.plans.expression.Not; +import com.amazon.opendistroforelasticsearch.sql.ppl.plans.expression.Or; +import com.amazon.opendistroforelasticsearch.sql.ppl.plans.expression.UnresolvedAttribute; +import com.amazon.opendistroforelasticsearch.sql.ppl.plans.logical.Aggregation; +import com.amazon.opendistroforelasticsearch.sql.ppl.plans.logical.Filter; +import com.amazon.opendistroforelasticsearch.sql.ppl.plans.logical.Project; +import com.amazon.opendistroforelasticsearch.sql.ppl.plans.logical.Relation; + +/** + * AST nodes visitor + * Defines the traverse path + */ +public abstract class AbstractNodeVisitor { + + public T visit(Node node, C context) { + return null; + } + + public T visitChildren(Node node, C context) { + T result = defaultResult(); + + for (Node child : node.getChild()) { + T childResult = child.accept(this, context); + result = aggregateResult(result, childResult); + } + return result; + } + + private T defaultResult() { + return null; + } + + private T aggregateResult(T aggregate, T nextResult) { + return nextResult; + } + + public T visitRelation(Relation node, C context) { + return visitChildren(node, context); + } + + public T visitFilter(Filter node, C context) { + return visitChildren(node, context); + } + + public T visitProject(Project node, C context) { + return visitChildren(node, context); + } + + public T visitAggregation(Aggregation node, C context) { + return visitChildren(node, context); + } + + public T visitEqualTo(EqualTo node, C context) { + return visitChildren(node, context); + } + + public T visitLiteral(Literal node, C context) { + return visitChildren(node, context); + } + + public T visitUnresolvedAttribute(UnresolvedAttribute node, C context) { + return visitChildren(node, context); + } + + public T visitAttributeList(AttributeList node, C context) { + return visitChildren(node, context); + } + + public T visitMap(Map node, C context) { + return visitChildren(node, context); + } + + public T visitNot(Not node, C context) { + return visitChildren(node, context); + } + + public T visitOr(Or node, C context) { + return visitChildren(node, context); + } + + public T visitAnd(And node, C context) { + return visitChildren(node, context); + } + + public T visitAggregateFunction(AggregateFunction node, C context) { + return visitChildren(node, context); + } + + public T visitFunction(Function node, C context) { + return visitChildren(node, context); + } + + public T visitIn(In node, C context) { + return visitChildren(node, context); + } + +} + diff --git a/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/node/Node.java b/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/node/Node.java new file mode 100644 index 0000000000..2732e06067 --- /dev/null +++ b/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/node/Node.java @@ -0,0 +1,36 @@ +/* + * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.amazon.opendistroforelasticsearch.sql.ppl.node; + +import java.util.List; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +/** + * AST node + */ +@EqualsAndHashCode +@ToString +public abstract class Node { + + public R accept(AbstractNodeVisitor visitor, C context) { + return visitor.visitChildren(this, context); + } + + public List getChild() { + return null; + } +} diff --git a/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/parser/AstBuilder.java b/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/parser/AstBuilder.java new file mode 100644 index 0000000000..83ff24d9eb --- /dev/null +++ b/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/parser/AstBuilder.java @@ -0,0 +1,197 @@ +/* + * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.amazon.opendistroforelasticsearch.sql.ppl.parser; + +import com.amazon.opendistroforelasticsearch.sql.common.utils.StringUtils; +import com.amazon.opendistroforelasticsearch.sql.ppl.antlr.parser.OpenDistroPPLParserBaseVisitor; +import com.amazon.opendistroforelasticsearch.sql.ppl.plans.expression.Expression; +import com.amazon.opendistroforelasticsearch.sql.ppl.plans.expression.Map; +import com.amazon.opendistroforelasticsearch.sql.ppl.plans.logical.Aggregation; +import com.amazon.opendistroforelasticsearch.sql.ppl.plans.logical.Filter; +import com.amazon.opendistroforelasticsearch.sql.ppl.plans.logical.UnresolvedPlan; +import com.amazon.opendistroforelasticsearch.sql.ppl.plans.logical.Project; +import com.amazon.opendistroforelasticsearch.sql.ppl.plans.logical.Relation; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; +import lombok.RequiredArgsConstructor; +import org.antlr.v4.runtime.tree.ParseTree; + +import static com.amazon.opendistroforelasticsearch.sql.ppl.antlr.parser.OpenDistroPPLParser.DedupCommandContext; +import static com.amazon.opendistroforelasticsearch.sql.ppl.antlr.parser.OpenDistroPPLParser.EvalCommandContext; +import static com.amazon.opendistroforelasticsearch.sql.ppl.antlr.parser.OpenDistroPPLParser.FieldsCommandContext; +import static com.amazon.opendistroforelasticsearch.sql.ppl.antlr.parser.OpenDistroPPLParser.FromClauseContext; +import static com.amazon.opendistroforelasticsearch.sql.ppl.antlr.parser.OpenDistroPPLParser.PplStatementContext; +import static com.amazon.opendistroforelasticsearch.sql.ppl.antlr.parser.OpenDistroPPLParser.RenameCommandContext; +import static com.amazon.opendistroforelasticsearch.sql.ppl.antlr.parser.OpenDistroPPLParser.SearchFilterFromContext; +import static com.amazon.opendistroforelasticsearch.sql.ppl.antlr.parser.OpenDistroPPLParser.SearchFromContext; +import static com.amazon.opendistroforelasticsearch.sql.ppl.antlr.parser.OpenDistroPPLParser.SearchFromFilterContext; +import static com.amazon.opendistroforelasticsearch.sql.ppl.antlr.parser.OpenDistroPPLParser.SortCommandContext; +import static com.amazon.opendistroforelasticsearch.sql.ppl.antlr.parser.OpenDistroPPLParser.StatsCommandContext; +import static com.amazon.opendistroforelasticsearch.sql.ppl.antlr.parser.OpenDistroPPLParser.WhereCommandContext; + +/** + * Class of building the AST + * Refines the visit path and build the AST nodes + */ +@RequiredArgsConstructor +public class AstBuilder extends OpenDistroPPLParserBaseVisitor { + private final AstExpressionBuilder expressionBuilder; + + @Override + public UnresolvedPlan visitPplStatement(PplStatementContext ctx) { + UnresolvedPlan search = visit(ctx.searchCommand()); + return ctx.commands() + .stream() + .map(this::visit) + .reduce(search, (r, e) -> e.attach(r)); + } + + /** Search command */ + @Override + public UnresolvedPlan visitSearchFrom(SearchFromContext ctx) { + return visitFromClause(ctx.fromClause()); + } + + @Override + public UnresolvedPlan visitSearchFromFilter(SearchFromFilterContext ctx) { + return new Filter(visitExpression(ctx.logicalExpression())).attach(visit(ctx.fromClause())); + } + + @Override + public UnresolvedPlan visitSearchFilterFrom(SearchFilterFromContext ctx) { + return new Filter(visitExpression(ctx.logicalExpression())).attach(visit(ctx.fromClause())); + } + + /** Where command */ + @Override + public UnresolvedPlan visitWhereCommand(WhereCommandContext ctx) { + return new Filter(visitExpression(ctx.logicalExpression())); + } + + /** Fields command */ + @Override + public UnresolvedPlan visitFieldsCommand(FieldsCommandContext ctx) { + return new Project( + ctx.wcFieldList() + .wcFieldExpression() + .stream() + .map(this::visitExpression) + .collect(Collectors.toList()) + ); + } + + /** Rename command */ + @Override + public UnresolvedPlan visitRenameCommand(RenameCommandContext ctx) { + return new Project( + new ArrayList<>( + Collections.singletonList( + new Map( + visitExpression(ctx.orignalField), + visitExpression(ctx.renamedField) + ) + ) + ) + ); + } + + /** Stats command */ + @Override + public UnresolvedPlan visitStatsCommand(StatsCommandContext ctx) { + List groupList = ctx.byClause() == null ? null : + ctx.byClause() + .fieldList() + .fieldExpression() + .stream() + .map(this::visitExpression) + .collect(Collectors.toList()); + return new Aggregation( + new ArrayList<>(Collections.singletonList(visitExpression(ctx.statsAggTerm()))), + null, + groupList + ); + } + + /** Dedup command */ + @Override + public UnresolvedPlan visitDedupCommand(DedupCommandContext ctx) { + List sortList = ctx.sortbyClause() == null ? null : + ctx.sortbyClause() + .sortField() + .stream() + .map(this::visitExpression) + .collect(Collectors.toList()); + return new Aggregation( + ctx.fieldList() + .fieldExpression() + .stream() + .map(this::visitExpression) + .collect(Collectors.toList()), + sortList, + null + ); + } + + /** Sort command */ + @Override + public UnresolvedPlan visitSortCommand(SortCommandContext ctx) { + return new Aggregation( + null, + ctx.sortbyClause() + .sortField() + .stream() + .map(this::visitExpression) + .collect(Collectors.toList()), + null + ); + } + + /** Eval command */ + @Override + public UnresolvedPlan visitEvalCommand(EvalCommandContext ctx) { + return new Project( + ctx.evalExpression() + .stream() + .map(this::visitExpression) + .collect(Collectors.toList()) + ); + } + + /** From clause */ + @Override + public UnresolvedPlan visitFromClause(FromClauseContext ctx) { + return new Relation(StringUtils.unquoteIdentifier(ctx.tableSource().getText())); + } + + /** Navigate to & build AST expression */ + private Expression visitExpression(ParseTree tree) { + return expressionBuilder.visit(tree); + } + + /** + * Simply return non-default value for now + */ + @Override + protected UnresolvedPlan aggregateResult(UnresolvedPlan aggregate, UnresolvedPlan nextResult) { + if (nextResult != defaultResult()) { + return nextResult; + } + return aggregate; + } + +} diff --git a/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/parser/AstExpressionBuilder.java b/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/parser/AstExpressionBuilder.java new file mode 100644 index 0000000000..2e34474757 --- /dev/null +++ b/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/parser/AstExpressionBuilder.java @@ -0,0 +1,177 @@ +/* + * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.amazon.opendistroforelasticsearch.sql.ppl.parser; + +import com.amazon.opendistroforelasticsearch.sql.ppl.antlr.parser.OpenDistroPPLParserBaseVisitor; +import com.amazon.opendistroforelasticsearch.sql.ppl.plans.expression.AggregateFunction; +import com.amazon.opendistroforelasticsearch.sql.ppl.plans.expression.And; +import com.amazon.opendistroforelasticsearch.sql.ppl.plans.expression.DataType; +import com.amazon.opendistroforelasticsearch.sql.ppl.plans.expression.EqualTo; +import com.amazon.opendistroforelasticsearch.sql.ppl.plans.expression.Expression; +import com.amazon.opendistroforelasticsearch.sql.ppl.plans.expression.Function; +import com.amazon.opendistroforelasticsearch.sql.ppl.plans.expression.In; +import com.amazon.opendistroforelasticsearch.sql.ppl.plans.expression.Literal; +import com.amazon.opendistroforelasticsearch.sql.ppl.plans.expression.Not; +import com.amazon.opendistroforelasticsearch.sql.ppl.plans.expression.Or; +import com.amazon.opendistroforelasticsearch.sql.ppl.plans.expression.UnresolvedAttribute; +import java.util.stream.Collectors; + +import static com.amazon.opendistroforelasticsearch.sql.ppl.antlr.parser.OpenDistroPPLParser.AggFunctionCallContext; +import static com.amazon.opendistroforelasticsearch.sql.ppl.antlr.parser.OpenDistroPPLParser.AggFunctionNameContext; +import static com.amazon.opendistroforelasticsearch.sql.ppl.antlr.parser.OpenDistroPPLParser.BooleanExpressionContext; +import static com.amazon.opendistroforelasticsearch.sql.ppl.antlr.parser.OpenDistroPPLParser.BooleanLiteralContext; +import static com.amazon.opendistroforelasticsearch.sql.ppl.antlr.parser.OpenDistroPPLParser.CompareExprContext; +import static com.amazon.opendistroforelasticsearch.sql.ppl.antlr.parser.OpenDistroPPLParser.DecimalLiteralContext; +import static com.amazon.opendistroforelasticsearch.sql.ppl.antlr.parser.OpenDistroPPLParser.EvalExpressionContext; +import static com.amazon.opendistroforelasticsearch.sql.ppl.antlr.parser.OpenDistroPPLParser.EvalFunctionCallContext; +import static com.amazon.opendistroforelasticsearch.sql.ppl.antlr.parser.OpenDistroPPLParser.EvalFunctionNameContext; +import static com.amazon.opendistroforelasticsearch.sql.ppl.antlr.parser.OpenDistroPPLParser.FieldExpressionContext; +import static com.amazon.opendistroforelasticsearch.sql.ppl.antlr.parser.OpenDistroPPLParser.InExprContext; +import static com.amazon.opendistroforelasticsearch.sql.ppl.antlr.parser.OpenDistroPPLParser.IntegerLiteralContext; +import static com.amazon.opendistroforelasticsearch.sql.ppl.antlr.parser.OpenDistroPPLParser.LogicalAndContext; +import static com.amazon.opendistroforelasticsearch.sql.ppl.antlr.parser.OpenDistroPPLParser.LogicalNotContext; +import static com.amazon.opendistroforelasticsearch.sql.ppl.antlr.parser.OpenDistroPPLParser.LogicalOrContext; +import static com.amazon.opendistroforelasticsearch.sql.ppl.antlr.parser.OpenDistroPPLParser.StringLiteralContext; +import static com.amazon.opendistroforelasticsearch.sql.ppl.antlr.parser.OpenDistroPPLParser.WcFieldExpressionContext; + +/** + * Class of building AST Expression nodes + */ +public class AstExpressionBuilder extends OpenDistroPPLParserBaseVisitor { + /** Logical expression excluding boolean, eval, comparison */ + @Override + public Expression visitLogicalNot(LogicalNotContext ctx) { + return new Not(visit(ctx.logicalExpression())); + } + + @Override + public Expression visitLogicalOr(LogicalOrContext ctx) { + return new Or(visit(ctx.left), visit(ctx.right)); + } + + @Override + public Expression visitLogicalAnd(LogicalAndContext ctx) { + return new And(visit(ctx.left), visit(ctx.right)); + } + + + /** Eval expression */ + @Override + public Expression visitEvalExpression(EvalExpressionContext ctx) { + Expression field = visit(ctx.fieldExpression()); + Expression evalFunctionCall = visit(ctx.evalFunctionCall()); + return new EqualTo(field, evalFunctionCall); + } + + /** Comparison expression */ + @Override + public Expression visitCompareExpr(CompareExprContext ctx) { + Expression field = visit(ctx.left); + Expression value = visit(ctx.right); + String operator = ctx.comparisonOperator().getText(); + switch (operator) { + case "==": + case "=": + return new EqualTo(field, value); + default: + throw new UnsupportedOperationException(String.format("unsupported operator [%s]", operator)); + } + } + + @Override + public Expression visitInExpr(InExprContext ctx) { + return new In( + visit(ctx.fieldExpression()), + ctx.valueList() + .literalValue() + .stream() + .map(this::visitLiteralValue) + .collect(Collectors.toList())); + } + + /** Boolean expression */ + @Override + public Expression visitBooleanExpression(BooleanExpressionContext ctx) { + return new Literal(ctx.booleanLiteral().getText(), DataType.BOOLEAN); + } + + + /** Field expression */ + @Override + public Expression visitFieldExpression(FieldExpressionContext ctx) { + return new UnresolvedAttribute(ctx.getText()); + } + + @Override + public Expression visitWcFieldExpression(WcFieldExpressionContext ctx) { + return new UnresolvedAttribute(ctx.getText()); + } + + /** Aggregation term */ + + /** Aggregation function */ + @Override + public Expression visitAggFunctionCall(AggFunctionCallContext ctx) { + return new AggregateFunction(ctx.aggFunctionName().getText(), visit(ctx.fieldExpression())); + } + + @Override + public Expression visitAggFunctionName(AggFunctionNameContext ctx) { + return new UnresolvedAttribute(ctx.getText()); + } + + /** Eval function */ + @Override + public Expression visitEvalFunctionCall(EvalFunctionCallContext ctx) { + return new Function( + ctx.evalFunctionName().getText(), + ctx.functionArgs() + .functionArg() + .stream() + .map(this::visitFunctionArg) + .collect(Collectors.toList())); + } + + @Override + public Expression visitEvalFunctionName(EvalFunctionNameContext ctx) { + return new UnresolvedAttribute(ctx.getText()); + } + + /** Literal and value */ + @Override + public Expression visitStringLiteral(StringLiteralContext ctx) { + String token = ctx.getText(); + String identifier = token.substring(1, token.length() - 1) + .replace("\"\"", "\""); + return new Literal(identifier, DataType.STRING); + } + + @Override + public Expression visitIntegerLiteral(IntegerLiteralContext ctx) { + return new Literal(Integer.valueOf(ctx.getText()), DataType.INTEGER); + } + + @Override + public Expression visitDecimalLiteral(DecimalLiteralContext ctx) { + return new Literal(Double.valueOf(ctx.getText()), DataType.DOUBLE); + } + + @Override + public Expression visitBooleanLiteral(BooleanLiteralContext ctx) { + return new Literal(Boolean.valueOf(ctx.getText()), DataType.BOOLEAN); + } + +} diff --git a/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/plans/dsl/DSL.java b/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/plans/dsl/DSL.java new file mode 100644 index 0000000000..1b05ddd275 --- /dev/null +++ b/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/plans/dsl/DSL.java @@ -0,0 +1,116 @@ +/* + * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.amazon.opendistroforelasticsearch.sql.ppl.plans.dsl; + +import com.amazon.opendistroforelasticsearch.sql.ppl.plans.expression.AggregateFunction; +import com.amazon.opendistroforelasticsearch.sql.ppl.plans.expression.And; +import com.amazon.opendistroforelasticsearch.sql.ppl.plans.expression.DataType; +import com.amazon.opendistroforelasticsearch.sql.ppl.plans.expression.EqualTo; +import com.amazon.opendistroforelasticsearch.sql.ppl.plans.expression.Expression; +import com.amazon.opendistroforelasticsearch.sql.ppl.plans.expression.Function; +import com.amazon.opendistroforelasticsearch.sql.ppl.plans.expression.In; +import com.amazon.opendistroforelasticsearch.sql.ppl.plans.expression.Literal; +import com.amazon.opendistroforelasticsearch.sql.ppl.plans.expression.Map; +import com.amazon.opendistroforelasticsearch.sql.ppl.plans.expression.Not; +import com.amazon.opendistroforelasticsearch.sql.ppl.plans.expression.Or; +import com.amazon.opendistroforelasticsearch.sql.ppl.plans.expression.UnresolvedAttribute; +import com.amazon.opendistroforelasticsearch.sql.ppl.plans.logical.Aggregation; +import com.amazon.opendistroforelasticsearch.sql.ppl.plans.logical.Filter; +import com.amazon.opendistroforelasticsearch.sql.ppl.plans.logical.UnresolvedPlan; +import com.amazon.opendistroforelasticsearch.sql.ppl.plans.logical.Project; +import com.amazon.opendistroforelasticsearch.sql.ppl.plans.logical.Relation; +import java.util.Arrays; +import java.util.List; + +/** + * Class of static methods to create specific node instances + */ +public class DSL { + + public static UnresolvedPlan filter(UnresolvedPlan input, Expression expression) { + return new Filter(expression).attach(input); + } + + public static UnresolvedPlan relation(String tableName) { + return new Relation(tableName); + } + + public static UnresolvedPlan project(UnresolvedPlan input, Expression... projectList) { + return new Project(Arrays.asList(projectList)).attach(input); + } + + public static UnresolvedPlan agg(UnresolvedPlan input, List aggList, List sortList, + List groupList) { + return new Aggregation(aggList, sortList, groupList).attach(input); + } + + public static Expression equalTo(Expression left, Expression right) { + return new EqualTo(left, right); + } + + public static Expression unresolvedAttr(String attr) { + return new UnresolvedAttribute(attr); + } + + private static Expression literal(Object value, DataType type) { + return new Literal(value, type); + } + + public static Expression intLiteral(Integer value) { + return literal(value, DataType.INTEGER); + } + + public static Expression doubleLiteral(Double value) { + return literal(value, DataType.DOUBLE); + } + + public static Expression stringLiteral(String value) { + return literal(value, DataType.STRING); + } + + public static Expression booleanLiteral(Boolean value) { + return literal(value, DataType.BOOLEAN); + } + + public static Expression map(String origin, String target) { + return new Map(new UnresolvedAttribute(origin), new UnresolvedAttribute(target)); + } + + public static Expression aggregate(String func, Expression field) { + return new AggregateFunction(func, field); + } + + public static Expression function(String funcName, Expression... funcArgs) { + return new Function(funcName, Arrays.asList(funcArgs)); + } + + public static Expression not(Expression expression) { + return new Not(expression); + } + + public static Expression or(Expression left, Expression right) { + return new Or(left, right); + } + + public static Expression and(Expression left, Expression right) { + return new And(left, right); + } + + public static Expression in(Expression field, Expression... valueList) { + return new In(field, Arrays.asList(valueList)); + } + +} diff --git a/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/plans/expression/AggregateFunction.java b/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/plans/expression/AggregateFunction.java new file mode 100644 index 0000000000..5ebcd474f9 --- /dev/null +++ b/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/plans/expression/AggregateFunction.java @@ -0,0 +1,47 @@ +/* + * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.amazon.opendistroforelasticsearch.sql.ppl.plans.expression; + +import com.amazon.opendistroforelasticsearch.sql.ppl.node.AbstractNodeVisitor; +import java.util.Arrays; +import java.util.List; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.ToString; + +/** + * Expression node of aggregate functions + * Params include aggregate function name (AVG, SUM, MAX etc.) and the field to aggregate + */ +@Getter +@ToString +@EqualsAndHashCode(callSuper = false) +@RequiredArgsConstructor +public class AggregateFunction extends Expression { + private final String funcName; + private final Expression field; + + @Override + public List getChild() { + return Arrays.asList(field); + } + + @Override + public R accept(AbstractNodeVisitor nodeVisitor, C context) { + return nodeVisitor.visitAggregateFunction(this, context); + } +} diff --git a/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/plans/expression/And.java b/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/plans/expression/And.java new file mode 100644 index 0000000000..1ca2f25609 --- /dev/null +++ b/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/plans/expression/And.java @@ -0,0 +1,46 @@ +/* + * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.amazon.opendistroforelasticsearch.sql.ppl.plans.expression; + +import com.amazon.opendistroforelasticsearch.sql.ppl.node.AbstractNodeVisitor; +import java.util.Arrays; +import java.util.List; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.ToString; + +/** + * Expression node of logic AND + */ +@Getter +@ToString +@EqualsAndHashCode(callSuper = false) +@RequiredArgsConstructor +public class And extends Expression { + private final Expression left; + private final Expression right; + + @Override + public List getChild() { + return Arrays.asList(left, right); + } + + @Override + public R accept(AbstractNodeVisitor nodeVisitor, C context) { + return nodeVisitor.visitAnd(this, context); + } +} diff --git a/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/plans/expression/AttributeList.java b/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/plans/expression/AttributeList.java new file mode 100644 index 0000000000..6853ade9c6 --- /dev/null +++ b/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/plans/expression/AttributeList.java @@ -0,0 +1,45 @@ +/* + * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.amazon.opendistroforelasticsearch.sql.ppl.plans.expression; + +import com.amazon.opendistroforelasticsearch.sql.ppl.node.AbstractNodeVisitor; +import com.google.common.collect.ImmutableList; +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.ToString; + +/** + * Expression node that includes a list of Expression nodes + */ +@ToString +@EqualsAndHashCode(callSuper = false) +@AllArgsConstructor +public class AttributeList extends Expression { + @Getter + private List attrList; + + @Override + public List getChild() { + return ImmutableList.of(); + } + + @Override + public R accept(AbstractNodeVisitor nodeVisitor, C context) { + return nodeVisitor.visitAttributeList(this, context); + } +} diff --git a/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/plans/expression/DataType.java b/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/plans/expression/DataType.java new file mode 100644 index 0000000000..5c08a9f85f --- /dev/null +++ b/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/plans/expression/DataType.java @@ -0,0 +1,26 @@ +/* + * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.amazon.opendistroforelasticsearch.sql.ppl.plans.expression; + +public enum DataType { + TYPE_ERROR, + NULL, + + INTEGER, + DOUBLE, + STRING, + BOOLEAN +} diff --git a/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/plans/expression/EqualTo.java b/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/plans/expression/EqualTo.java new file mode 100644 index 0000000000..f399900f0c --- /dev/null +++ b/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/plans/expression/EqualTo.java @@ -0,0 +1,47 @@ +/* + * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.amazon.opendistroforelasticsearch.sql.ppl.plans.expression; + +import com.amazon.opendistroforelasticsearch.sql.ppl.node.AbstractNodeVisitor; +import java.util.Arrays; +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.ToString; + +/** + * Expression node of binary operator or comparison relation EQUAL + */ +@ToString +@EqualsAndHashCode(callSuper = false) +@AllArgsConstructor +public class EqualTo extends Expression { + @Getter + private Expression left; + @Getter + private Expression right; + + @Override + public List getChild() { + return Arrays.asList(left, right); + } + + @Override + public R accept(AbstractNodeVisitor nodeVisitor, C context) { + return nodeVisitor.visitEqualTo(this, context); + } +} diff --git a/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/plans/expression/Expression.java b/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/plans/expression/Expression.java new file mode 100644 index 0000000000..4909aa5ad1 --- /dev/null +++ b/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/plans/expression/Expression.java @@ -0,0 +1,30 @@ +/* + * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.amazon.opendistroforelasticsearch.sql.ppl.plans.expression; + +import com.amazon.opendistroforelasticsearch.sql.ppl.node.AbstractNodeVisitor; +import com.amazon.opendistroforelasticsearch.sql.ppl.node.Node; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@EqualsAndHashCode(callSuper = false) +@ToString +public abstract class Expression extends Node { + @Override + public T accept(AbstractNodeVisitor nodeVisitor, C context) { + return nodeVisitor.visitChildren(this, context); + } +} diff --git a/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/plans/expression/Function.java b/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/plans/expression/Function.java new file mode 100644 index 0000000000..c6d8649fcc --- /dev/null +++ b/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/plans/expression/Function.java @@ -0,0 +1,47 @@ +/* + * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.amazon.opendistroforelasticsearch.sql.ppl.plans.expression; + +import com.amazon.opendistroforelasticsearch.sql.ppl.node.AbstractNodeVisitor; +import com.google.common.collect.ImmutableList; +import java.util.List; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.ToString; + +/** + * Expression node of scalar function + * Params include function name (@funcName) and function arguments (@funcArgs) + */ +@Getter +@ToString +@EqualsAndHashCode(callSuper = false) +@RequiredArgsConstructor +public class Function extends Expression { + private final String funcName; + private final List funcArgs; + + @Override + public List getChild() { + return ImmutableList.of(); + } + + @Override + public R accept(AbstractNodeVisitor nodeVisitor, C context) { + return nodeVisitor.visitFunction(this, context); + } +} diff --git a/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/plans/expression/In.java b/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/plans/expression/In.java new file mode 100644 index 0000000000..1899afef18 --- /dev/null +++ b/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/plans/expression/In.java @@ -0,0 +1,48 @@ +/* + * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.amazon.opendistroforelasticsearch.sql.ppl.plans.expression; + +import com.amazon.opendistroforelasticsearch.sql.ppl.node.AbstractNodeVisitor; +import java.util.Arrays; +import java.util.List; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.ToString; + +/** + * Expression node of one-to-many mapping relation IN + * Params include the field expression and/or wildcard field expression, nested field expression (@field) + * And the values that the field is mapped to (@valueList) + */ +@Getter +@ToString +@EqualsAndHashCode(callSuper = false) +@RequiredArgsConstructor +public class In extends Expression { + private final Expression field; + private final List valueList; + + @Override + public List getChild() { + return Arrays.asList(field); + } + + @Override + public R accept(AbstractNodeVisitor nodeVisitor, C context) { + return nodeVisitor.visitIn(this, context); + } +} diff --git a/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/plans/expression/Literal.java b/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/plans/expression/Literal.java new file mode 100644 index 0000000000..a5427161c5 --- /dev/null +++ b/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/plans/expression/Literal.java @@ -0,0 +1,48 @@ +/* + * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.amazon.opendistroforelasticsearch.sql.ppl.plans.expression; + +import com.amazon.opendistroforelasticsearch.sql.ppl.node.AbstractNodeVisitor; +import com.google.common.collect.ImmutableList; +import java.util.List; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.ToString; + +/** + * Expression node of literal type + * Params include literal value (@value) and literal data type (@type) which can be selected from {@link DataType} + */ +@Getter +@ToString +@EqualsAndHashCode(callSuper = false) +@RequiredArgsConstructor +public class Literal extends Expression { + + private final Object value; + private final DataType type; + + @Override + public List getChild() { + return ImmutableList.of(); + } + + @Override + public R accept(AbstractNodeVisitor nodeVisitor, C context) { + return nodeVisitor.visitLiteral(this, context); + } +} diff --git a/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/plans/expression/Map.java b/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/plans/expression/Map.java new file mode 100644 index 0000000000..eb9bf7b7a2 --- /dev/null +++ b/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/plans/expression/Map.java @@ -0,0 +1,46 @@ +/* + * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.amazon.opendistroforelasticsearch.sql.ppl.plans.expression; + +import com.amazon.opendistroforelasticsearch.sql.ppl.node.AbstractNodeVisitor; +import java.util.Arrays; +import java.util.List; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.ToString; + +/** + * Expression node of one-to-one mapping relation + */ +@Getter +@ToString +@EqualsAndHashCode(callSuper = false) +@RequiredArgsConstructor +public class Map extends Expression { + private final Expression origin; + private final Expression target; + + @Override + public List getChild() { + return Arrays.asList(origin, target); + } + + @Override + public R accept(AbstractNodeVisitor nodeVisitor, C context) { + return nodeVisitor.visitMap(this, context); + } +} diff --git a/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/plans/expression/Not.java b/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/plans/expression/Not.java new file mode 100644 index 0000000000..2c1e667e22 --- /dev/null +++ b/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/plans/expression/Not.java @@ -0,0 +1,45 @@ +/* + * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.amazon.opendistroforelasticsearch.sql.ppl.plans.expression; + +import com.amazon.opendistroforelasticsearch.sql.ppl.node.AbstractNodeVisitor; +import java.util.Arrays; +import java.util.List; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.ToString; + +/** + * Expression node of the logic NOT + */ +@Getter +@ToString +@EqualsAndHashCode(callSuper = false) +@RequiredArgsConstructor +public class Not extends Expression { + private final Expression expression; + + @Override + public List getChild() { + return Arrays.asList(expression); + } + + @Override + public R accept(AbstractNodeVisitor nodeVisitor, C context) { + return nodeVisitor.visitNot(this, context); + } +} diff --git a/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/plans/expression/Or.java b/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/plans/expression/Or.java new file mode 100644 index 0000000000..a5498e7ee7 --- /dev/null +++ b/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/plans/expression/Or.java @@ -0,0 +1,46 @@ +/* + * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.amazon.opendistroforelasticsearch.sql.ppl.plans.expression; + +import com.amazon.opendistroforelasticsearch.sql.ppl.node.AbstractNodeVisitor; +import java.util.Arrays; +import java.util.List; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.ToString; + +/** + * Expression node of the logic OR + */ +@Getter +@ToString +@EqualsAndHashCode(callSuper = false) +@RequiredArgsConstructor +public class Or extends Expression { + private final Expression left; + private final Expression right; + + @Override + public List getChild() { + return Arrays.asList(left, right); + } + + @Override + public R accept(AbstractNodeVisitor nodeVisitor, C context) { + return nodeVisitor.visitOr(this, context); + } +} diff --git a/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/plans/expression/UnresolvedAttribute.java b/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/plans/expression/UnresolvedAttribute.java new file mode 100644 index 0000000000..0df3fa7279 --- /dev/null +++ b/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/plans/expression/UnresolvedAttribute.java @@ -0,0 +1,46 @@ +/* + * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.amazon.opendistroforelasticsearch.sql.ppl.plans.expression; + +import com.amazon.opendistroforelasticsearch.sql.ppl.node.AbstractNodeVisitor; +import com.google.common.collect.ImmutableList; +import java.util.List; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.ToString; + +/** + * Expression node, representing the syntax that is not resolved to any other expression nodes yet but non-negligible + * This expression is often created as the index name, field name etc. + */ +@ToString +@EqualsAndHashCode(callSuper = false) +@RequiredArgsConstructor +@Getter +public class UnresolvedAttribute extends Expression { + private final String attr; + + @Override + public List getChild() { + return ImmutableList.of(); + } + + @Override + public R accept(AbstractNodeVisitor nodeVisitor, C context) { + return nodeVisitor.visitUnresolvedAttribute(this, context); + } +} diff --git a/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/plans/logical/Aggregation.java b/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/plans/logical/Aggregation.java new file mode 100644 index 0000000000..157958f3ad --- /dev/null +++ b/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/plans/logical/Aggregation.java @@ -0,0 +1,64 @@ +/* + * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.amazon.opendistroforelasticsearch.sql.ppl.plans.logical; + +import com.amazon.opendistroforelasticsearch.sql.ppl.node.AbstractNodeVisitor; +import com.amazon.opendistroforelasticsearch.sql.ppl.plans.expression.Expression; +import com.google.common.collect.ImmutableList; +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +/** + * Logical plan node of Aggregation, the interface for building aggregation actions in queries + */ +@Getter +@Setter +@ToString +@EqualsAndHashCode(callSuper = false) +@AllArgsConstructor +public class Aggregation extends UnresolvedPlan { + private List aggExprList; + private List sortExprList; + private List groupExprList; + private UnresolvedPlan child; + + public Aggregation(List aggExprList, List sortExprList, List groupExprList) { + this.aggExprList = aggExprList; + this.sortExprList = sortExprList; + this.groupExprList = groupExprList; + } + + @Override + public Aggregation attach(UnresolvedPlan child) { + this.child = child; + return this; + } + + + @Override + public List getChild() { + return ImmutableList.of(this.child); + } + + @Override + public T accept(AbstractNodeVisitor nodeVisitor, C context) { + return nodeVisitor.visitAggregation(this, context); + } +} diff --git a/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/plans/logical/Filter.java b/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/plans/logical/Filter.java new file mode 100644 index 0000000000..24a771c076 --- /dev/null +++ b/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/plans/logical/Filter.java @@ -0,0 +1,55 @@ +/* + * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.amazon.opendistroforelasticsearch.sql.ppl.plans.logical; + +import com.amazon.opendistroforelasticsearch.sql.ppl.node.AbstractNodeVisitor; +import com.amazon.opendistroforelasticsearch.sql.ppl.plans.expression.Expression; +import com.google.common.collect.ImmutableList; +import java.util.List; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.ToString; + +/** + * Logical plan node of Filter, the interface for building filters in queries + */ +@ToString +@EqualsAndHashCode(callSuper = false) +@Getter +public class Filter extends UnresolvedPlan { + private Expression condition; + private UnresolvedPlan child; + + public Filter(Expression condition) { + this.condition = condition; + } + + @Override + public Filter attach(UnresolvedPlan child) { + this.child = child; + return this; + } + + @Override + public List getChild() { + return ImmutableList.of(child); + } + + @Override + public T accept(AbstractNodeVisitor nodeVisitor, C context) { + return nodeVisitor.visitFilter(this, context); + } +} diff --git a/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/plans/logical/Project.java b/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/plans/logical/Project.java new file mode 100644 index 0000000000..f0c2867962 --- /dev/null +++ b/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/plans/logical/Project.java @@ -0,0 +1,60 @@ +/* + * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.amazon.opendistroforelasticsearch.sql.ppl.plans.logical; + +import com.amazon.opendistroforelasticsearch.sql.ppl.node.AbstractNodeVisitor; +import com.amazon.opendistroforelasticsearch.sql.ppl.plans.expression.Expression; +import com.google.common.collect.ImmutableList; +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +/** + * Logical plan node of Project, the interface for building the list of searching fields + */ +@ToString +@Getter +@EqualsAndHashCode(callSuper = false) +@AllArgsConstructor +public class Project extends UnresolvedPlan { + @Setter + private List projectList; + private UnresolvedPlan child; + + public Project(List projectList) { + this.projectList = projectList; + } + + @Override + public Project attach(UnresolvedPlan child) { + this.child = child; + return this; + } + + @Override + public List getChild() { + return ImmutableList.of(this.child); + } + + @Override + public T accept(AbstractNodeVisitor nodeVisitor, C context) { + + return nodeVisitor.visitProject(this, context); + } +} diff --git a/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/plans/logical/Relation.java b/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/plans/logical/Relation.java new file mode 100644 index 0000000000..9233f5a5dd --- /dev/null +++ b/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/plans/logical/Relation.java @@ -0,0 +1,50 @@ +/* + * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.amazon.opendistroforelasticsearch.sql.ppl.plans.logical; + +import com.amazon.opendistroforelasticsearch.sql.ppl.node.AbstractNodeVisitor; +import com.google.common.collect.ImmutableList; +import java.util.List; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.ToString; + +/** + * Logical plan node of Relation, the interface for building the searching sources + */ +@Getter +@ToString +@EqualsAndHashCode(callSuper = false) +@RequiredArgsConstructor +public class Relation extends UnresolvedPlan { + private final String tableName; + + @Override + public List getChild() { + return ImmutableList.of(); + } + + @Override + public T accept(AbstractNodeVisitor nodeVisitor, C context) { + return nodeVisitor.visitRelation(this, context); + } + + @Override + public UnresolvedPlan attach(UnresolvedPlan child) { + return this; + } +} diff --git a/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/plans/logical/UnresolvedPlan.java b/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/plans/logical/UnresolvedPlan.java new file mode 100644 index 0000000000..74fa01df8a --- /dev/null +++ b/ppl/src/main/java/com/amazon/opendistroforelasticsearch/sql/ppl/plans/logical/UnresolvedPlan.java @@ -0,0 +1,35 @@ +/* + * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.amazon.opendistroforelasticsearch.sql.ppl.plans.logical; + +import com.amazon.opendistroforelasticsearch.sql.ppl.node.AbstractNodeVisitor; +import com.amazon.opendistroforelasticsearch.sql.ppl.node.Node; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +/** + * Abstract unresolved plan + */ +@EqualsAndHashCode(callSuper = false) +@ToString +public abstract class UnresolvedPlan extends Node { + @Override + public T accept(AbstractNodeVisitor nodeVisitor, C context) { + return nodeVisitor.visitChildren(this, context); + } + + public abstract UnresolvedPlan attach(UnresolvedPlan child); +} diff --git a/ppl/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/parser/AstBuilderTest.java b/ppl/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/parser/AstBuilderTest.java new file mode 100644 index 0000000000..b186e57edf --- /dev/null +++ b/ppl/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/parser/AstBuilderTest.java @@ -0,0 +1,164 @@ +/* + * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.amazon.opendistroforelasticsearch.sql.ppl.parser; + +import com.amazon.opendistroforelasticsearch.sql.ppl.antlr.PPLSyntaxParser; +import com.amazon.opendistroforelasticsearch.sql.ppl.node.Node; +import java.util.Arrays; +import java.util.Collections; +import org.junit.Test; +import static com.amazon.opendistroforelasticsearch.sql.ppl.plans.dsl.DSL.agg; +import static com.amazon.opendistroforelasticsearch.sql.ppl.plans.dsl.DSL.aggregate; +import static com.amazon.opendistroforelasticsearch.sql.ppl.plans.dsl.DSL.equalTo; +import static com.amazon.opendistroforelasticsearch.sql.ppl.plans.dsl.DSL.filter; +import static com.amazon.opendistroforelasticsearch.sql.ppl.plans.dsl.DSL.function; +import static com.amazon.opendistroforelasticsearch.sql.ppl.plans.dsl.DSL.intLiteral; +import static com.amazon.opendistroforelasticsearch.sql.ppl.plans.dsl.DSL.map; +import static com.amazon.opendistroforelasticsearch.sql.ppl.plans.dsl.DSL.project; +import static com.amazon.opendistroforelasticsearch.sql.ppl.plans.dsl.DSL.relation; +import static com.amazon.opendistroforelasticsearch.sql.ppl.plans.dsl.DSL.stringLiteral; +import static com.amazon.opendistroforelasticsearch.sql.ppl.plans.dsl.DSL.unresolvedAttr; +import static org.junit.Assert.assertEquals; + +public class AstBuilderTest { + + @Test + public void testSearchCommand() { + assertEqual("search source=t a=1", + filter( + relation("t"), + equalTo(unresolvedAttr("a"), intLiteral(1)) + ) + ); + } + + @Test + public void testSearchCommandString() { + assertEqual("search source=t a=\"a\"", + filter( + relation("t"), + equalTo(unresolvedAttr("a"), stringLiteral("a")) + ) + ); + } + + @Test + public void testSearchCommandWithoutSearch() { + assertEqual("source=t a=1", + filter( + relation("t"), + equalTo(unresolvedAttr("a"), intLiteral(1)) + ) + ); + } + + @Test + public void testWhereCommand() { + assertEqual("search source=t | where a=1", + filter( + relation("t"), + equalTo(unresolvedAttr("a"), intLiteral(1)) + ) + ); + } + + @Test + public void testFieldsCommand() { + assertEqual("source=t | fields f, g", + project( + relation("t"), + unresolvedAttr("f"), unresolvedAttr("g") + )); + } + + @Test + public void testRenameCommand() { + assertEqual("source=t | rename f as g", + project( + relation("t"), + map("f", "g") + )); + } + + @Test + public void testStatsCommand() { + assertEqual("source=t | stats count(a) by b", + agg( + relation("t"), + Collections.singletonList( + aggregate( + "count", unresolvedAttr("a") + )), + null, + Collections.singletonList(unresolvedAttr("b")) + )); + } + + @Test + public void testDedupCommand() { + assertEqual("source=t | dedup f1, f2 sortby f3", + agg( + relation("t"), + Arrays.asList(unresolvedAttr("f1"), unresolvedAttr("f2")), + Collections.singletonList(unresolvedAttr("f3")), + null + )); + } + + @Test + public void testSortCommand() { + assertEqual("source=t | sort f1, f2", + agg( + relation("t"), + null, + Arrays.asList(unresolvedAttr("f1"), unresolvedAttr("f2")), + null + )); + } + + @Test + public void testEvalCommand() { + assertEqual("source=t | eval r=abs(f)", + project( + relation("t"), + equalTo( + unresolvedAttr("r"), + function("abs", unresolvedAttr("f")) + ) + )); + } + + @Test + public void testIndexName() { + assertEqual("source=\"log.2020.04.20.\" a=1", + filter( + relation("log.2020.04.20."), + equalTo(unresolvedAttr("a"), intLiteral(1)) + )); + } + + protected void assertEqual(String query, Node expectedPlan) { + Node actualPlan = plan(query); + assertEquals(expectedPlan, actualPlan); + } + + private PPLSyntaxParser parser = new PPLSyntaxParser(); + private AstBuilder astBuilder = new AstBuilder(new AstExpressionBuilder()); + + private Node plan(String query) { + return astBuilder.visit(parser.analyzeSyntax(query)); + } +} diff --git a/ppl/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/parser/AstExpressionBuilderTest.java b/ppl/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/parser/AstExpressionBuilderTest.java new file mode 100644 index 0000000000..6ace3b21c0 --- /dev/null +++ b/ppl/src/test/java/com/amazon/opendistroforelasticsearch/sql/ppl/parser/AstExpressionBuilderTest.java @@ -0,0 +1,202 @@ +/* + * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.amazon.opendistroforelasticsearch.sql.ppl.parser; + +import java.util.Collections; +import org.junit.Test; +import static com.amazon.opendistroforelasticsearch.sql.ppl.plans.dsl.DSL.agg; +import static com.amazon.opendistroforelasticsearch.sql.ppl.plans.dsl.DSL.aggregate; +import static com.amazon.opendistroforelasticsearch.sql.ppl.plans.dsl.DSL.and; +import static com.amazon.opendistroforelasticsearch.sql.ppl.plans.dsl.DSL.booleanLiteral; +import static com.amazon.opendistroforelasticsearch.sql.ppl.plans.dsl.DSL.doubleLiteral; +import static com.amazon.opendistroforelasticsearch.sql.ppl.plans.dsl.DSL.equalTo; +import static com.amazon.opendistroforelasticsearch.sql.ppl.plans.dsl.DSL.filter; +import static com.amazon.opendistroforelasticsearch.sql.ppl.plans.dsl.DSL.function; +import static com.amazon.opendistroforelasticsearch.sql.ppl.plans.dsl.DSL.in; +import static com.amazon.opendistroforelasticsearch.sql.ppl.plans.dsl.DSL.intLiteral; +import static com.amazon.opendistroforelasticsearch.sql.ppl.plans.dsl.DSL.not; +import static com.amazon.opendistroforelasticsearch.sql.ppl.plans.dsl.DSL.or; +import static com.amazon.opendistroforelasticsearch.sql.ppl.plans.dsl.DSL.project; +import static com.amazon.opendistroforelasticsearch.sql.ppl.plans.dsl.DSL.relation; +import static com.amazon.opendistroforelasticsearch.sql.ppl.plans.dsl.DSL.stringLiteral; +import static com.amazon.opendistroforelasticsearch.sql.ppl.plans.dsl.DSL.unresolvedAttr; + +public class AstExpressionBuilderTest extends AstBuilderTest{ + + @Test + public void testLogicalNotExpr() { + assertEqual("source=t not a=1", + filter( + relation("t"), + not( + equalTo(unresolvedAttr("a"), intLiteral(1)) + ) + )); + } + + @Test + public void testLogicalOrExpr() { + assertEqual("source=t a=1 or b=2", + filter( + relation("t"), + or( + equalTo(unresolvedAttr("a"), intLiteral(1)), + equalTo(unresolvedAttr("b"), intLiteral(2)) + ) + )); + } + + @Test + public void testLogicalAndExpr() { + assertEqual("source=t a=1 and b=2", + filter( + relation("t"), + and( + equalTo(unresolvedAttr("a"), intLiteral(1)), + equalTo(unresolvedAttr("b"), intLiteral(2)) + ) + )); + } + + @Test + public void testLogicalAndExprWithoutKeywordAnd() { + assertEqual("source=t a=1 b=2", + filter( + relation("t"), + and( + equalTo(unresolvedAttr("a"), intLiteral(1)), + equalTo(unresolvedAttr("b"), intLiteral(2)) + ) + )); + } + + @Test + public void testEvalExpr() { + assertEqual("source=t f=abs(a)", + filter( + relation("t"), + equalTo( + unresolvedAttr("f"), + function("abs", unresolvedAttr("a")) + ) + )); + } + + @Test + public void testCompareExprWhenEqual() { + assertEqual("source=t a='b'", + filter( + relation("t"), + equalTo(unresolvedAttr("a"), stringLiteral("b")) + )); + } + + @Test + public void testInExpr() { + assertEqual("source=t f in (1, 2, 3)", + filter( + relation("t"), + in( + unresolvedAttr("f"), + intLiteral(1), intLiteral(2), intLiteral(3)) + )); + } + + @Test + public void testFieldExpr() { + assertEqual("source=t | sort +f", + agg( + relation("t"), + null, + Collections.singletonList(unresolvedAttr("f")), + null + )); + } + + @Test + public void testAggFuncCallExpr() { + assertEqual("source=t | stats avg(a) by b", + agg( + relation("t"), + Collections.singletonList( + aggregate("avg", unresolvedAttr("a")) + ), + null, + Collections.singletonList(unresolvedAttr("b")) + )); + } + + @Test + public void testEvalFuncCallExpr() { + assertEqual("source=t | eval f=abs(a)", + project( + relation("t"), + equalTo( + unresolvedAttr("f"), + function("abs", unresolvedAttr("a")) + ) + )); + } + + @Test + public void testStringLiteralExpr() { + assertEqual("source=t a=\"string\"", + filter( + relation("t"), + equalTo( + unresolvedAttr("a"), + stringLiteral("string") + ) + )); + } + + @Test + public void testIntegerLiteralExpr() { + assertEqual("source=t a=1", + filter( + relation("t"), + equalTo( + unresolvedAttr("a"), + intLiteral(1) + ) + )); + } + + @Test + public void testDoubleLiteralExpr() { + assertEqual("source=t b=0.1", + filter( + relation("t"), + equalTo( + unresolvedAttr("b"), + doubleLiteral(0.1) + ) + )); + } + + @Test + public void testBooleanLiteralExpr() { + assertEqual("source=t a=true", + filter( + relation("t"), + equalTo( + unresolvedAttr("a"), + booleanLiteral(true) + ) + )); + } + +}