wecharyu commented on code in PR #4344:
URL: https://github.com/apache/hive/pull/4344#discussion_r1214408721
##########
ql/src/test/results/clientpositive/llap/temp_table_partition_type_in_plan.q.out:
##########
@@ -32,11 +32,13 @@ PREHOOK: query: SELECT * FROM datePartTbl_temp WHERE
date_prt IN (CAST('2014-08-
PREHOOK: type: QUERY
PREHOOK: Input: default@dateparttbl_temp
PREHOOK: Input: default@dateparttbl_temp@date_prt=2014-08-09
+PREHOOK: Input: default@dateparttbl_temp@date_prt=2014-08-10
#### A masked pattern was here ####
POSTHOOK: query: SELECT * FROM datePartTbl_temp WHERE date_prt IN
(CAST('2014-08-09' AS DATE), CAST('2014-08-08' AS DATE))
POSTHOOK: type: QUERY
POSTHOOK: Input: default@dateparttbl_temp
POSTHOOK: Input: default@dateparttbl_temp@date_prt=2014-08-09
+POSTHOOK: Input: default@dateparttbl_temp@date_prt=2014-08-10
Review Comment:
The new inExpression does not add parentheses for identifier, has fixed it.
##########
standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/parser/AstBuilder.java:
##########
@@ -0,0 +1,266 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License 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 org.apache.hadoop.hive.metastore.parser;
+
+import java.sql.Date;
+import java.sql.Timestamp;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
+import java.util.List;
+import java.util.Locale;
+import java.util.TimeZone;
+import java.util.stream.Collectors;
+
+import org.antlr.v4.runtime.misc.ParseCancellationException;
+import org.antlr.v4.runtime.tree.RuleNode;
+import org.antlr.v4.runtime.tree.TerminalNode;
+
+import static org.apache.hadoop.hive.metastore.parser.ExpressionTree.LeafNode;
+import static
org.apache.hadoop.hive.metastore.parser.ExpressionTree.LogicalOperator;
+import static org.apache.hadoop.hive.metastore.parser.ExpressionTree.Operator;
+import static org.apache.hadoop.hive.metastore.parser.ExpressionTree.TreeNode;
+
+public class AstBuilder extends PartitionFilterBaseVisitor<Object> {
+ private final DateTimeFormatter dateFormat =
+ DateTimeFormatter.ofPattern("yyyy-MM-dd")
+ .withZone(TimeZone.getTimeZone("UTC").toZoneId());
+ private final DateTimeFormatter timestampFormat =
+ DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
+ .withZone(TimeZone.getTimeZone("UTC").toZoneId());
+
+ /**
+ * Override the default behavior for all visit methods. This will only
return a non-null result
+ * when the context has only one child. This is done because there is no
generic method to
+ * combine the results of the context children. In all other cases null is
returned.
+ */
+ @Override
+ public Object visitChildren(RuleNode node) {
+ if (node.getChildCount() == 1) {
+ return node.getChild(0).accept(this);
+ }
+ return null;
+ }
+
+ @Override
+ public ExpressionTree visitFilter(PartitionFilterParser.FilterContext ctx) {
+ ExpressionTree tree = new ExpressionTree();
+ TreeNode treeNode = (TreeNode) visit(ctx.filterExpression());
+ tree.setRoot(treeNode);
+ return tree;
+ }
+
+ @Override
+ public TreeNode
visitSingleCondition(PartitionFilterParser.SingleConditionContext ctx) {
+ return (TreeNode) visit(ctx.conditionExpression());
+ }
+
+ @Override
+ public TreeNode
visitParenedFilter(PartitionFilterParser.ParenedFilterContext ctx) {
+ return (TreeNode) visit(ctx.filterExpression());
+ }
+
+ @Override
+ public TreeNode visitBinaryFilter(PartitionFilterParser.BinaryFilterContext
ctx) {
+ TreeNode left = (TreeNode) visit(ctx.left);
+ TreeNode right = (TreeNode) visit(ctx.right);
+ LogicalOperator operator = visitLogicOperator(ctx.logicOperator());
+ return new TreeNode(left, operator, right);
+ }
+
+ @Override
+ public TreeNode visitComparison(PartitionFilterParser.ComparisonContext ctx)
{
+ LeafNode leafNode = new LeafNode();
+ leafNode.keyName = ctx.key.getText();
+ leafNode.value = visit(ctx.value);
+ leafNode.operator = visitComparisonOperator(ctx.comparisonOperator());
+ return leafNode;
+ }
+
+ @Override
+ public Object
visitReverseComparison(PartitionFilterParser.ReverseComparisonContext ctx) {
+ LeafNode leafNode = new LeafNode();
+ leafNode.keyName = ctx.key.getText();
+ leafNode.value = visit(ctx.value);
+ leafNode.operator = visitComparisonOperator(ctx.comparisonOperator());
+ leafNode.isReverseOrder = true;
+ return leafNode;
+ }
+
+ @Override
+ public TreeNode
visitBetweenCondition(PartitionFilterParser.BetweenConditionContext ctx) {
+ LeafNode left = new LeafNode();
+ LeafNode right = new LeafNode();
+ left.keyName = right.keyName = ctx.key.getText();
+ left.value = visit(ctx.lower);
+ right.value = visit(ctx.upper);
+
+ boolean isPositive = ctx.NOT() == null;
+ left.operator = isPositive ? Operator.GREATERTHANOREQUALTO :
Operator.LESSTHAN;
+ right.operator = isPositive ? Operator.LESSTHANOREQUALTO :
Operator.GREATERTHAN;
+ LogicalOperator rootOperator = isPositive ? LogicalOperator.AND :
LogicalOperator.OR;
+
+ return new TreeNode(left, rootOperator, right);
+ }
+
+ @Override
+ public TreeNode visitInCondition(PartitionFilterParser.InConditionContext
ctx) {
+ List<Object> values = visitConstantSeq(ctx.constantSeq());
+ boolean isPositive = ctx.NOT() == null;
+ String keyName = ctx.key.getText();
+
+ TreeNode root = null;
+ for (int i = 0; i < values.size(); ++i) {
+ LeafNode leafNode = new LeafNode();
+ leafNode.keyName = keyName;
+ leafNode.value = values.get(i);
+ leafNode.operator = isPositive ? Operator.EQUALS : Operator.NOTEQUALS2;
+
+ if (i == 0) {
+ root = leafNode;
+ } else {
+ root = new TreeNode(root, isPositive ? LogicalOperator.OR :
LogicalOperator.AND, leafNode);
+ }
+ }
+
+ return root;
+ }
+
+ @Override
+ public TreeNode
visitMultiColInExpression(PartitionFilterParser.MultiColInExpressionContext
ctx) {
+ TreeNode root = new TreeNode();
+ List<String> keyNames = visitIdentifierList(ctx.identifierList());
+ List<List<Object>> structs = visitConstStructList(ctx.constStructList());
+ boolean isPositive = ctx.NOT() == null;
+ for (int i = 0; i < structs.size(); ++i) {
+ List<Object> struct = structs.get(i);
+ if (keyNames.size() != struct.size()) {
+ throw new ParseCancellationException("Struct key " + keyNames + " does
not match value " + struct);
+ }
Review Comment:
We need to check for each struct among `structs`, so I think check here is
also acceptable.
##########
standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/parser/PartFilterParser.java:
##########
@@ -0,0 +1,127 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License 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 org.apache.hadoop.hive.metastore.parser;
+
+import java.util.function.Function;
+
+import org.antlr.v4.runtime.*;
+import org.antlr.v4.runtime.misc.Interval;
+import org.antlr.v4.runtime.misc.ParseCancellationException;
+import org.apache.hadoop.hive.metastore.api.MetaException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class PartFilterParser {
+ private static final Logger LOG =
LoggerFactory.getLogger(PartFilterParser.class);
+ private static final ThreadLocal<AstBuilder> astBuilder =
ThreadLocal.withInitial(AstBuilder::new);
Review Comment:
Yes, we should use separate instance of parser, lexer, visitor in parallel
threads.
##########
standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/parser/PartitionFilter.g4:
##########
@@ -0,0 +1,149 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License 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.
+
+grammar PartitionFilter;
+
+filter
+ : filterExpression
+ ;
+
+filterExpression
+ : conditionExpression
#singleCondition
+ | LPAREN filterExpression RPAREN #parenedFilter
+ | left=filterExpression logicOperator right=filterExpression #binaryFilter
Review Comment:
The precedence logic can be handled in `PartFilterVisitor#visitBinaryFilter`.
##########
standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/parser/AstBuilder.java:
##########
@@ -0,0 +1,266 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License 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 org.apache.hadoop.hive.metastore.parser;
+
+import java.sql.Date;
+import java.sql.Timestamp;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
+import java.util.List;
+import java.util.Locale;
+import java.util.TimeZone;
+import java.util.stream.Collectors;
+
+import org.antlr.v4.runtime.misc.ParseCancellationException;
+import org.antlr.v4.runtime.tree.RuleNode;
+import org.antlr.v4.runtime.tree.TerminalNode;
+
+import static org.apache.hadoop.hive.metastore.parser.ExpressionTree.LeafNode;
+import static
org.apache.hadoop.hive.metastore.parser.ExpressionTree.LogicalOperator;
+import static org.apache.hadoop.hive.metastore.parser.ExpressionTree.Operator;
+import static org.apache.hadoop.hive.metastore.parser.ExpressionTree.TreeNode;
+
+public class AstBuilder extends PartitionFilterBaseVisitor<Object> {
+ private final DateTimeFormatter dateFormat =
+ DateTimeFormatter.ofPattern("yyyy-MM-dd")
+ .withZone(TimeZone.getTimeZone("UTC").toZoneId());
+ private final DateTimeFormatter timestampFormat =
+ DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
+ .withZone(TimeZone.getTimeZone("UTC").toZoneId());
+
+ /**
+ * Override the default behavior for all visit methods. This will only
return a non-null result
+ * when the context has only one child. This is done because there is no
generic method to
+ * combine the results of the context children. In all other cases null is
returned.
+ */
+ @Override
+ public Object visitChildren(RuleNode node) {
+ if (node.getChildCount() == 1) {
Review Comment:
Since we have written visitor for each rule, it seems not exist node with
more than one children need to parse. And I have not got an example like this.
##########
standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/parser/AstBuilder.java:
##########
@@ -0,0 +1,266 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License 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 org.apache.hadoop.hive.metastore.parser;
+
+import java.sql.Date;
+import java.sql.Timestamp;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
+import java.util.List;
+import java.util.Locale;
+import java.util.TimeZone;
+import java.util.stream.Collectors;
+
+import org.antlr.v4.runtime.misc.ParseCancellationException;
+import org.antlr.v4.runtime.tree.RuleNode;
+import org.antlr.v4.runtime.tree.TerminalNode;
+
+import static org.apache.hadoop.hive.metastore.parser.ExpressionTree.LeafNode;
+import static
org.apache.hadoop.hive.metastore.parser.ExpressionTree.LogicalOperator;
+import static org.apache.hadoop.hive.metastore.parser.ExpressionTree.Operator;
+import static org.apache.hadoop.hive.metastore.parser.ExpressionTree.TreeNode;
+
+public class AstBuilder extends PartitionFilterBaseVisitor<Object> {
+ private final DateTimeFormatter dateFormat =
+ DateTimeFormatter.ofPattern("yyyy-MM-dd")
+ .withZone(TimeZone.getTimeZone("UTC").toZoneId());
+ private final DateTimeFormatter timestampFormat =
+ DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
+ .withZone(TimeZone.getTimeZone("UTC").toZoneId());
Review Comment:
Followed your PR.
##########
standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/parser/AstBuilder.java:
##########
@@ -0,0 +1,266 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License 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 org.apache.hadoop.hive.metastore.parser;
+
+import java.sql.Date;
+import java.sql.Timestamp;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
+import java.util.List;
+import java.util.Locale;
+import java.util.TimeZone;
+import java.util.stream.Collectors;
+
+import org.antlr.v4.runtime.misc.ParseCancellationException;
+import org.antlr.v4.runtime.tree.RuleNode;
+import org.antlr.v4.runtime.tree.TerminalNode;
+
+import static org.apache.hadoop.hive.metastore.parser.ExpressionTree.LeafNode;
+import static
org.apache.hadoop.hive.metastore.parser.ExpressionTree.LogicalOperator;
+import static org.apache.hadoop.hive.metastore.parser.ExpressionTree.Operator;
+import static org.apache.hadoop.hive.metastore.parser.ExpressionTree.TreeNode;
+
+public class AstBuilder extends PartitionFilterBaseVisitor<Object> {
Review Comment:
Done.
##########
standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/parser/PartitionFilter.g4:
##########
@@ -0,0 +1,149 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License 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.
+
+grammar PartitionFilter;
+
+filter
+ : filterExpression
+ ;
+
+filterExpression
+ : conditionExpression
#singleCondition
+ | LPAREN filterExpression RPAREN #parenedFilter
+ | left=filterExpression logicOperator right=filterExpression #binaryFilter
+ ;
+
+conditionExpression
+ : key=identifier comparisonOperator value=constant #comparison
+ | value=constant comparisonOperator key=identifier
#reverseComparison
+ | key=identifier NOT? BETWEEN lower=constant AND upper=constant
#betweenCondition
+ | key=identifier NOT? IN LPAREN values=constantSeq RPAREN
#inCondition
+ | LPAREN STRUCT identifierList RPAREN NOT? IN constStructList
#multiColInExpression
+ ;
+
+logicOperator
+ : AND | OR
+ ;
+
+comparisonOperator
+ : EQ | NEQ | NEQJ | LT | LTE | GT | GTE | NSEQ | LIKE
+ ;
+
+identifier
+ : IDENTIFIER #unquotedIdentifer
+ ;
+
+identifierList
+ : LPAREN ident+=identifier (COMMA ident+=identifier)* RPAREN
+ ;
+
+constant
+ : STRING+ #stringLiteral
+ | number #numericLiteral
+ | date #dateLiteral
+ | timestamp #timestampLiteral
+ ;
+
+constantSeq
+ : values+=constant (COMMA values+=constant)*
+ ;
+
+constStruct
+ : CONST STRUCT LPAREN constantSeq RPAREN
+ ;
+
+constStructList
+ : LPAREN structs+=constStruct (COMMA structs+=constStruct) RPAREN
+ ;
+
+number
+ : MINUS? INTEGER_VALUE #integerLiteral
+ ;
+
+date
+ : DATE value=STRING
Review Comment:
It does not support this rule:
```g4
date
: DATE '\'' value=DATE_VALUE '\''
| value=DATE_VALUE
;
```
I have tries lots of replacement, still not work. 😢
##########
standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/parser/PartFilterParser.java:
##########
@@ -0,0 +1,127 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License 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 org.apache.hadoop.hive.metastore.parser;
+
+import java.util.function.Function;
+
+import org.antlr.v4.runtime.*;
+import org.antlr.v4.runtime.misc.Interval;
+import org.antlr.v4.runtime.misc.ParseCancellationException;
+import org.apache.hadoop.hive.metastore.api.MetaException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class PartFilterParser {
+ private static final Logger LOG =
LoggerFactory.getLogger(PartFilterParser.class);
+ private static final ThreadLocal<AstBuilder> astBuilder =
ThreadLocal.withInitial(AstBuilder::new);
+
+ public static ExpressionTree parseFilter(String filter) throws MetaException
{
+ return parse(filter, parser ->
astBuilder.get().visitFilter(parser.filter()));
+ }
+
+ private static <T> T parse(String filter, Function<PartitionFilterParser, T>
toResult)
+ throws MetaException {
+ LOG.debug("Parsing filter: " + filter);
+ CharStream upperCaseCharStream = new
UpperCaseCharStream(CharStreams.fromString(filter));
+ PartitionFilterLexer lexer = new PartitionFilterLexer(upperCaseCharStream);
+ lexer.removeErrorListeners();
+ lexer.addErrorListener(ParseErrorListener.INSTANCE);
+
+ CommonTokenStream tokenStream = new CommonTokenStream(lexer);
+ PartitionFilterParser parser = new PartitionFilterParser(tokenStream);
+ parser.removeErrorListeners();
+ parser.addErrorListener(ParseErrorListener.INSTANCE);
+
+ try {
+ return toResult.apply(parser);
+ } catch (ParseCancellationException e) {
+ throw new MetaException("Error parsing partition filter: " +
e.getMessage());
+ }
+ }
+
+ /** Case-insensitive ANTLR string stream */
+ private static class UpperCaseCharStream implements CharStream {
Review Comment:
`CodePointCharStream` has only a private constructor, so we can not extends
it.
##########
standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/parser/AstBuilder.java:
##########
@@ -0,0 +1,266 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License 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 org.apache.hadoop.hive.metastore.parser;
+
+import java.sql.Date;
+import java.sql.Timestamp;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
+import java.util.List;
+import java.util.Locale;
+import java.util.TimeZone;
+import java.util.stream.Collectors;
+
+import org.antlr.v4.runtime.misc.ParseCancellationException;
+import org.antlr.v4.runtime.tree.RuleNode;
+import org.antlr.v4.runtime.tree.TerminalNode;
+
+import static org.apache.hadoop.hive.metastore.parser.ExpressionTree.LeafNode;
+import static
org.apache.hadoop.hive.metastore.parser.ExpressionTree.LogicalOperator;
+import static org.apache.hadoop.hive.metastore.parser.ExpressionTree.Operator;
+import static org.apache.hadoop.hive.metastore.parser.ExpressionTree.TreeNode;
+
+public class AstBuilder extends PartitionFilterBaseVisitor<Object> {
+ private final DateTimeFormatter dateFormat =
+ DateTimeFormatter.ofPattern("yyyy-MM-dd")
+ .withZone(TimeZone.getTimeZone("UTC").toZoneId());
+ private final DateTimeFormatter timestampFormat =
+ DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
+ .withZone(TimeZone.getTimeZone("UTC").toZoneId());
+
+ /**
+ * Override the default behavior for all visit methods. This will only
return a non-null result
+ * when the context has only one child. This is done because there is no
generic method to
+ * combine the results of the context children. In all other cases null is
returned.
+ */
+ @Override
+ public Object visitChildren(RuleNode node) {
+ if (node.getChildCount() == 1) {
+ return node.getChild(0).accept(this);
+ }
+ return null;
+ }
+
+ @Override
+ public ExpressionTree visitFilter(PartitionFilterParser.FilterContext ctx) {
+ ExpressionTree tree = new ExpressionTree();
+ TreeNode treeNode = (TreeNode) visit(ctx.filterExpression());
+ tree.setRoot(treeNode);
+ return tree;
+ }
+
+ @Override
+ public TreeNode
visitSingleCondition(PartitionFilterParser.SingleConditionContext ctx) {
+ return (TreeNode) visit(ctx.conditionExpression());
+ }
+
+ @Override
+ public TreeNode
visitParenedFilter(PartitionFilterParser.ParenedFilterContext ctx) {
+ return (TreeNode) visit(ctx.filterExpression());
+ }
+
+ @Override
+ public TreeNode visitBinaryFilter(PartitionFilterParser.BinaryFilterContext
ctx) {
+ TreeNode left = (TreeNode) visit(ctx.left);
+ TreeNode right = (TreeNode) visit(ctx.right);
+ LogicalOperator operator = visitLogicOperator(ctx.logicOperator());
+ return new TreeNode(left, operator, right);
+ }
+
+ @Override
+ public TreeNode visitComparison(PartitionFilterParser.ComparisonContext ctx)
{
+ LeafNode leafNode = new LeafNode();
+ leafNode.keyName = ctx.key.getText();
+ leafNode.value = visit(ctx.value);
+ leafNode.operator = visitComparisonOperator(ctx.comparisonOperator());
+ return leafNode;
+ }
+
+ @Override
+ public Object
visitReverseComparison(PartitionFilterParser.ReverseComparisonContext ctx) {
+ LeafNode leafNode = new LeafNode();
+ leafNode.keyName = ctx.key.getText();
+ leafNode.value = visit(ctx.value);
+ leafNode.operator = visitComparisonOperator(ctx.comparisonOperator());
+ leafNode.isReverseOrder = true;
+ return leafNode;
+ }
+
+ @Override
+ public TreeNode
visitBetweenCondition(PartitionFilterParser.BetweenConditionContext ctx) {
+ LeafNode left = new LeafNode();
+ LeafNode right = new LeafNode();
+ left.keyName = right.keyName = ctx.key.getText();
+ left.value = visit(ctx.lower);
+ right.value = visit(ctx.upper);
+
+ boolean isPositive = ctx.NOT() == null;
+ left.operator = isPositive ? Operator.GREATERTHANOREQUALTO :
Operator.LESSTHAN;
+ right.operator = isPositive ? Operator.LESSTHANOREQUALTO :
Operator.GREATERTHAN;
+ LogicalOperator rootOperator = isPositive ? LogicalOperator.AND :
LogicalOperator.OR;
+
+ return new TreeNode(left, rootOperator, right);
+ }
+
+ @Override
+ public TreeNode visitInCondition(PartitionFilterParser.InConditionContext
ctx) {
+ List<Object> values = visitConstantSeq(ctx.constantSeq());
+ boolean isPositive = ctx.NOT() == null;
+ String keyName = ctx.key.getText();
+
+ TreeNode root = null;
+ for (int i = 0; i < values.size(); ++i) {
+ LeafNode leafNode = new LeafNode();
+ leafNode.keyName = keyName;
+ leafNode.value = values.get(i);
+ leafNode.operator = isPositive ? Operator.EQUALS : Operator.NOTEQUALS2;
+
+ if (i == 0) {
+ root = leafNode;
+ } else {
+ root = new TreeNode(root, isPositive ? LogicalOperator.OR :
LogicalOperator.AND, leafNode);
+ }
+ }
+
+ return root;
+ }
+
+ @Override
+ public TreeNode
visitMultiColInExpression(PartitionFilterParser.MultiColInExpressionContext
ctx) {
+ TreeNode root = new TreeNode();
+ List<String> keyNames = visitIdentifierList(ctx.identifierList());
+ List<List<Object>> structs = visitConstStructList(ctx.constStructList());
+ boolean isPositive = ctx.NOT() == null;
+ for (int i = 0; i < structs.size(); ++i) {
+ List<Object> struct = structs.get(i);
+ if (keyNames.size() != struct.size()) {
+ throw new ParseCancellationException("Struct key " + keyNames + " does
not match value " + struct);
+ }
+ TreeNode node = new TreeNode();
+ for (int j = 0; j < struct.size(); ++j) {
+ LeafNode leafNode = new LeafNode();
+ leafNode.keyName = keyNames.get(j);
+ leafNode.value = struct.get(j);
+ leafNode.operator = isPositive ? Operator.EQUALS : Operator.NOTEQUALS2;
+ if (j == 0) {
+ node = leafNode;
+ } else {
+ node = new TreeNode(node, isPositive ? LogicalOperator.AND :
LogicalOperator.OR, leafNode);
+ }
+ }
+ if (i == 0) {
+ root = node;
+ } else {
+ root = new TreeNode(root, isPositive ? LogicalOperator.OR :
LogicalOperator.AND, node);
+ }
+ }
+
+ return root;
+ }
+
+ @Override
+ public LogicalOperator
visitLogicOperator(PartitionFilterParser.LogicOperatorContext ctx) {
+ switch (ctx.getText().toUpperCase(Locale.ROOT)) {
+ case "AND": return LogicalOperator.AND;
+ case "OR": return LogicalOperator.OR;
+ default: return null;
+ }
+ }
+
+ @Override
+ public Operator
visitComparisonOperator(PartitionFilterParser.ComparisonOperatorContext ctx) {
+ TerminalNode node = (TerminalNode) ctx.getChild(0);
+ switch (node.getSymbol().getType()) {
+ case PartitionFilterParser.EQ: return Operator.EQUALS;
+ case PartitionFilterParser.NEQ: return Operator.NOTEQUALS;
+ case PartitionFilterParser.NEQJ: return Operator.NOTEQUALS2;
+ case PartitionFilterParser.LT: return Operator.LESSTHAN;
+ case PartitionFilterParser.LTE: return Operator.LESSTHANOREQUALTO;
+ case PartitionFilterParser.GT: return Operator.GREATERTHAN;
+ case PartitionFilterParser.GTE: return Operator.GREATERTHANOREQUALTO;
+ case PartitionFilterParser.LIKE: return Operator.LIKE;
+ }
+ return null;
+ }
+
+ @Override
+ public List<Object>
visitConstantSeq(PartitionFilterParser.ConstantSeqContext ctx) {
+ return ctx.values.stream().map(this::visit).collect(Collectors.toList());
+ }
+
+ @Override
+ public List<Object>
visitConstStruct(PartitionFilterParser.ConstStructContext ctx) {
+ return visitConstantSeq(ctx.constantSeq());
+ }
+
+ @Override
+ public List<List<Object>>
visitConstStructList(PartitionFilterParser.ConstStructListContext ctx) {
+ return
ctx.structs.stream().map(this::visitConstStruct).collect(Collectors.toList());
+ }
+
+ @Override
+ public List<String>
visitIdentifierList(PartitionFilterParser.IdentifierListContext ctx) {
+ return ctx.ident.stream().map(i ->
i.getText()).collect(Collectors.toList());
+ }
+
+ @Override
+ public String visitStringLiteral(PartitionFilterParser.StringLiteralContext
ctx) {
+ return unquoteString(ctx.getText());
+ }
+
+ private String unquoteString(String string) {
+ if (string.length() > 1) {
Review Comment:
`ctx.getText()` will never be null.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]