IMPALA-9035: Simplify casting string to timestamp.
This change will help with queries generated by some BI tools.
Case 1:
Simplify 'string -> bigint -> timestamp' TO 'string -> timestamp':
cast(unix_timestamp('timestr') as timestamp) ->
cast('timestr' as timestamp)
Case 2:
Simplify 'string[fmt] -> bigint -> timestamp' TO 'string -> timestamp':
cast(unix_timestamp('timestr', 'fmt') as timestamp) ->
to_timestamp('timestr', 'fmt')
Tests:
Add front-end tests in ExprRewriteRulesTest.
Change-Id: I4ed72d6e7886eaf50d2be60cf45170ffaef5e72d
Reviewed-on: http://gerrit.cloudera.org:8080/14896
Reviewed-by: Attila Jeges <attilaj@cloudera.com>
Tested-by: Impala Public Jenkins <impala-public-jenkins@cloudera.com>
diff --git a/fe/src/main/java/org/apache/impala/analysis/Analyzer.java b/fe/src/main/java/org/apache/impala/analysis/Analyzer.java
index 1ef542b..fd85322 100644
--- a/fe/src/main/java/org/apache/impala/analysis/Analyzer.java
+++ b/fe/src/main/java/org/apache/impala/analysis/Analyzer.java
@@ -71,6 +71,7 @@
import org.apache.impala.rewrite.NormalizeBinaryPredicatesRule;
import org.apache.impala.rewrite.NormalizeCountStarRule;
import org.apache.impala.rewrite.NormalizeExprsRule;
+import org.apache.impala.rewrite.SimplifyCastStringToTimestamp;
import org.apache.impala.rewrite.SimplifyConditionalsRule;
import org.apache.impala.rewrite.SimplifyDistinctFromRule;
import org.apache.impala.service.FeSupport;
@@ -483,6 +484,7 @@
rules.add(EqualityDisjunctsToInRule.INSTANCE);
rules.add(NormalizeCountStarRule.INSTANCE);
rules.add(SimplifyDistinctFromRule.INSTANCE);
+ rules.add(SimplifyCastStringToTimestamp.INSTANCE);
}
exprRewriter_ = new ExprRewriter(rules);
}
diff --git a/fe/src/main/java/org/apache/impala/rewrite/SimplifyCastStringToTimestamp.java b/fe/src/main/java/org/apache/impala/rewrite/SimplifyCastStringToTimestamp.java
new file mode 100644
index 0000000..af6ffd8
--- /dev/null
+++ b/fe/src/main/java/org/apache/impala/rewrite/SimplifyCastStringToTimestamp.java
@@ -0,0 +1,77 @@
+// 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.impala.rewrite;
+
+import org.apache.impala.analysis.Analyzer;
+import org.apache.impala.analysis.CastExpr;
+import org.apache.impala.analysis.Expr;
+import org.apache.impala.analysis.FunctionCallExpr;
+import org.apache.impala.analysis.FunctionName;
+import org.apache.impala.analysis.TypeDef;
+import org.apache.impala.common.AnalysisException;
+import com.google.common.collect.Lists;
+
+
+/**
+ ** Case 1:
+ ** Simplify 'string -> bigint -> timestamp' TO 'string -> timestamp':
+ ** cast(unix_timestamp('timestr') as timestamp) -> cast('timestr' as timestamp)
+ **
+ ** Case 2:
+ ** Simplify 'string[fmt] -> bigint -> timestamp' TO 'string -> timestamp':
+ ** cast(unix_timestamp('timestr', 'fmt') as timestamp) -> to_timestamp('timestr', 'fmt')
+ **/
+
+public class SimplifyCastStringToTimestamp implements ExprRewriteRule {
+ public static ExprRewriteRule INSTANCE = new SimplifyCastStringToTimestamp();
+
+ @Override
+ public Expr apply(Expr expr, Analyzer analyzer) throws AnalysisException {
+ if (expr instanceof CastExpr &&
+ !((CastExpr)expr).isImplicit() &&
+ expr.getChild(0) instanceof FunctionCallExpr) {
+ if (!expr.isAnalyzed())
+ expr.analyze(analyzer);
+
+ FunctionCallExpr fce = (FunctionCallExpr)expr.getChild(0);
+ if (!expr.getType().isTimestamp() ||
+ !fce.getFnName().getFunction().equalsIgnoreCase("unix_timestamp"))
+ return expr;
+
+ Expr simplifiedExpr = null;
+ if (fce.getChildren().size() == 1 &&
+ fce.getChild(0).getType().isStringType()) {
+ // Handle Case 1
+ simplifiedExpr = new CastExpr(new TypeDef(expr.getType()), fce.getChild(0));
+ } else if (fce.getChildren().size() == 2 &&
+ fce.getChild(0).getType().isStringType() &&
+ fce.getChild(1).getType().isStringType()) {
+ // Handle Case 2
+ simplifiedExpr = new FunctionCallExpr(new FunctionName("to_timestamp"),
+ Lists.newArrayList(fce.getChildren()));
+ }
+
+ if (simplifiedExpr != null) {
+ simplifiedExpr.analyze(analyzer);
+ return simplifiedExpr;
+ }
+ }
+
+ return expr;
+ }
+}
diff --git a/fe/src/test/java/org/apache/impala/analysis/ExprRewriteRulesTest.java b/fe/src/test/java/org/apache/impala/analysis/ExprRewriteRulesTest.java
index 40e6b5b..0635210 100644
--- a/fe/src/test/java/org/apache/impala/analysis/ExprRewriteRulesTest.java
+++ b/fe/src/test/java/org/apache/impala/analysis/ExprRewriteRulesTest.java
@@ -40,6 +40,7 @@
import org.apache.impala.rewrite.NormalizeBinaryPredicatesRule;
import org.apache.impala.rewrite.NormalizeCountStarRule;
import org.apache.impala.rewrite.NormalizeExprsRule;
+import org.apache.impala.rewrite.SimplifyCastStringToTimestamp;
import org.apache.impala.rewrite.SimplifyConditionalsRule;
import org.apache.impala.rewrite.SimplifyDistinctFromRule;
import org.junit.BeforeClass;
@@ -770,6 +771,21 @@
RewritesOk("if(bool_col <=> NULL, 1, 2)", rules, null);
}
+ @Test
+ public void testSimplifyCastStringToTimestamp() throws ImpalaException {
+ ExprRewriteRule rule = SimplifyCastStringToTimestamp.INSTANCE;
+
+ // Can be simplified
+ RewritesOk("cast(unix_timestamp(date_string_col) as timestamp)", rule,
+ "CAST(date_string_col AS TIMESTAMP)");
+ RewritesOk("cast(unix_timestamp(date_string_col, 'yyyy-MM-dd') as timestamp)", rule,
+ "to_timestamp(date_string_col, 'yyyy-MM-dd')");
+
+ // Verify nothing happens
+ RewritesOk("cast(unix_timestamp(timestamp_col) as timestamp)", rule, null);
+ RewritesOk("cast(unix_timestamp() as timestamp)", rule, null);
+ }
+
/**
* NULLIF gets converted to an IF, and has cases where
* it can be further simplified via SimplifyDistinctFromRule.