This is an automated email from the ASF dual-hosted git repository.

danny0405 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/calcite.git


The following commit(s) were added to refs/heads/master by this push:
     new 7df0678  [CALCITE-2933] Add timestamp extract for casts from timestamp 
type to other types
7df0678 is described below

commit 7df06784a725bd9bde421b5d86ac69a3e30d66b4
Author: yuzhao.cyz <[email protected]>
AuthorDate: Wed Mar 20 20:42:46 2019 +0800

    [CALCITE-2933] Add timestamp extract for casts from timestamp type to other 
types
    
    In Druid, timestamp is stored as a UTC long value, so the
    Cast(timestamp as varchar) should transform to date format string.
    
    Close apache/calcite#1120
---
 .../apache/calcite/adapter/druid/DruidQuery.java   | 32 ++++++++++++----------
 .../org/apache/calcite/test/DruidAdapterIT2.java   | 24 ++++++++++------
 2 files changed, 33 insertions(+), 23 deletions(-)

diff --git 
a/druid/src/main/java/org/apache/calcite/adapter/druid/DruidQuery.java 
b/druid/src/main/java/org/apache/calcite/adapter/druid/DruidQuery.java
index fe44de0..b9fd322 100644
--- a/druid/src/main/java/org/apache/calcite/adapter/druid/DruidQuery.java
+++ b/druid/src/main/java/org/apache/calcite/adapter/druid/DruidQuery.java
@@ -241,6 +241,14 @@ public class DruidQuery extends AbstractRelNode implements 
BindableRel {
         query.druidTable, intervals, query.rels, 
query.getOperatorConversionMap());
   }
 
+  /** Check if it is needed to use UTC for DATE and TIMESTAMP types. **/
+  private static boolean needUtcTimeExtract(RexNode rexNode) {
+    return rexNode.getType().getSqlTypeName() == SqlTypeName.DATE
+        || rexNode.getType().getSqlTypeName() == SqlTypeName.TIMESTAMP
+        || rexNode.getType().getSqlTypeName()
+        == SqlTypeName.TIMESTAMP_WITH_LOCAL_TIME_ZONE;
+  }
+
   /**
    * @param rexNode    leaf Input Ref to Druid Column
    * @param rowType    row type
@@ -257,11 +265,7 @@ public class DruidQuery extends AbstractRelNode implements 
BindableRel {
     switch (rexNode.getKind()) {
     case INPUT_REF:
       columnName = extractColumnName(rexNode, rowType, druidQuery);
-      if (rexNode.getType().getSqlTypeName() == SqlTypeName.DATE
-          || rexNode.getType().getSqlTypeName() == SqlTypeName.TIMESTAMP
-          || rexNode.getType().getSqlTypeName()
-          == SqlTypeName.TIMESTAMP_WITH_LOCAL_TIME_ZONE) {
-        // Use UTC for DATE and TIMESTAMP types
+      if (needUtcTimeExtract(rexNode)) {
         extractionFunction = TimeExtractionFunction.createDefault(
             DateTimeUtils.UTC_ZONE.getID());
       } else {
@@ -308,10 +312,7 @@ public class DruidQuery extends AbstractRelNode implements 
BindableRel {
         return Pair.of(null, null);
       }
       RexNode floorValueNode = ((RexCall) rexNode).getOperands().get(0);
-      if (floorValueNode.getType().getSqlTypeName() == SqlTypeName.DATE
-          || floorValueNode.getType().getSqlTypeName() == SqlTypeName.TIMESTAMP
-          || floorValueNode.getType().getSqlTypeName()
-          == SqlTypeName.TIMESTAMP_WITH_LOCAL_TIME_ZONE) {
+      if (needUtcTimeExtract(floorValueNode)) {
         // Use 'UTC' at the extraction level, since all datetime types
         // are represented in 'UTC'
         extractionFunction =
@@ -327,12 +328,11 @@ public class DruidQuery extends AbstractRelNode 
implements BindableRel {
       if (!isValidLeafCast(rexNode)) {
         return Pair.of(null, null);
       }
+      RexNode operand0 = ((RexCall) rexNode).getOperands().get(0);
       columnName =
-          extractColumnName(((RexCall) rexNode).getOperands().get(0), rowType, 
druidQuery);
-      // CASE CAST to TIME/DATE need to make sure that we have valid 
extraction fn
-      final SqlTypeName toTypeName = rexNode.getType().getSqlTypeName();
-      if (toTypeName == SqlTypeName.DATE || toTypeName == SqlTypeName.TIMESTAMP
-          || toTypeName == SqlTypeName.TIMESTAMP_WITH_LOCAL_TIME_ZONE) {
+          extractColumnName(operand0, rowType, druidQuery);
+      if (needUtcTimeExtract(rexNode)) {
+        // CASE CAST to TIME/DATE need to make sure that we have valid 
extraction fn
         extractionFunction = 
TimeExtractionFunction.translateCastToTimeExtract(rexNode,
             TimeZone.getTimeZone(druidQuery.getConnectionConfig().timeZone()));
         if (extractionFunction == null) {
@@ -761,7 +761,9 @@ public class DruidQuery extends AbstractRelNode implements 
BindableRel {
     for (RexNode project : projects) {
       Pair<String, ExtractionFunction> druidColumn =
           toDruidColumn(project, inputRowType, druidQuery);
-      if (druidColumn.left == null || druidColumn.right != null) {
+      boolean needExtractForOperand = project instanceof RexCall
+          && ((RexCall) 
project).getOperands().stream().anyMatch(DruidQuery::needUtcTimeExtract);
+      if (druidColumn.left == null || druidColumn.right != null || 
needExtractForOperand) {
         // It is a complex project pushed as expression
         final String expression = DruidExpressions
             .toDruidExpression(project, inputRowType, druidQuery);
diff --git a/druid/src/test/java/org/apache/calcite/test/DruidAdapterIT2.java 
b/druid/src/test/java/org/apache/calcite/test/DruidAdapterIT2.java
index 5c2b85b..6646492 100644
--- a/druid/src/test/java/org/apache/calcite/test/DruidAdapterIT2.java
+++ b/druid/src/test/java/org/apache/calcite/test/DruidAdapterIT2.java
@@ -25,7 +25,6 @@ import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.schema.impl.AbstractSchema;
 import org.apache.calcite.sql.fun.SqlStdOperatorTable;
 import org.apache.calcite.sql.type.SqlTypeName;
-import org.apache.calcite.util.Bug;
 import org.apache.calcite.util.TestUtil;
 
 import com.google.common.collect.ArrayListMultimap;
@@ -3927,16 +3926,25 @@ public class DruidAdapterIT2 {
   }
 
   @Test
-  public void testCastTimestamp() {
+  public void testCastTimestamp1() {
+    final String sql = "Select cast(\"timestamp\" as varchar) as t"
+        + " from \"foodmart\" order by t limit 1";
+
+    sql(sql, FOODMART)
+        .returnsOrdered("T=1997-01-01 00:00:00")
+        .queryContains(
+            druidChecker("UTC"));
+  }
+
+  @Test
+  public void testCastTimestamp2() {
     final String sql = "Select cast(cast(\"timestamp\" as timestamp) as 
varchar) as t"
         + " from \"foodmart\" order by t limit 1";
 
-    if (Bug.CALCITE_2933_FIXED) {
-      sql(sql, FOODMART)
-          .returnsOrdered("T=1997-01-01 00:00:00")
-          .queryContains(
-              druidChecker("UTC"));
-    }
+    sql(sql, FOODMART)
+        .returnsOrdered("T=1997-01-01 00:00:00")
+        .queryContains(
+            druidChecker("UTC"));
   }
 }
 

Reply via email to