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"));
}
}