You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by mm...@apache.org on 2017/09/07 01:50:48 UTC
[3/4] calcite git commit: [CALCITE-1947] Add time/timestamp with
local time zone types to optimizer
[CALCITE-1947] Add time/timestamp with local time zone types to optimizer
Close apache/calcite#519
Project: http://git-wip-us.apache.org/repos/asf/calcite/repo
Commit: http://git-wip-us.apache.org/repos/asf/calcite/commit/939c9a62
Tree: http://git-wip-us.apache.org/repos/asf/calcite/tree/939c9a62
Diff: http://git-wip-us.apache.org/repos/asf/calcite/diff/939c9a62
Branch: refs/heads/branch-1.14
Commit: 939c9a62b4905d2cfffcb4adaefd76a809aa3520
Parents: f10950b
Author: Jesus Camacho Rodriguez <jc...@apache.org>
Authored: Mon Aug 14 17:46:42 2017 -0700
Committer: Jesus Camacho Rodriguez <jc...@apache.org>
Committed: Tue Sep 5 15:00:36 2017 -0700
----------------------------------------------------------------------
.../calcite/adapter/enumerable/RexImpTable.java | 15 +-
.../adapter/enumerable/RexToLixTranslator.java | 153 +++++++++++
.../calcite/jdbc/JavaTypeFactoryImpl.java | 2 +
.../apache/calcite/rel/metadata/RelMdSize.java | 4 +
.../rel/rules/SortProjectTransposeRule.java | 3 +-
.../calcite/rel/type/RelDataTypeSystemImpl.java | 8 +
.../java/org/apache/calcite/rex/RexBuilder.java | 57 +++++
.../java/org/apache/calcite/rex/RexLiteral.java | 26 ++
.../org/apache/calcite/rex/RexSimplify.java | 1 +
.../apache/calcite/runtime/SqlFunctions.java | 98 ++++++++
.../java/org/apache/calcite/schema/Schemas.java | 4 +-
.../apache/calcite/sql/SqlJdbcDataTypeName.java | 2 +
.../sql/type/SqlTypeAssignmentRules.java | 34 +++
.../apache/calcite/sql/type/SqlTypeFamily.java | 6 +-
.../apache/calcite/sql/type/SqlTypeName.java | 11 +-
.../sql2rel/StandardConvertletTable.java | 26 ++
.../org/apache/calcite/util/BuiltInMethod.java | 28 ++-
.../org/apache/calcite/util/DateString.java | 2 +-
.../calcite/util/DateTimeStringUtils.java | 88 +++++++
.../org/apache/calcite/util/TimeString.java | 6 +-
.../calcite/util/TimeWithTimeZoneString.java | 188 ++++++++++++++
.../apache/calcite/util/TimestampString.java | 52 +---
.../util/TimestampWithTimeZoneString.java | 194 ++++++++++++++
.../calcite/jdbc/CalciteRemoteDriverTest.java | 2 +-
.../org/apache/calcite/rex/RexBuilderTest.java | 73 ++++++
.../org/apache/calcite/test/CalciteAssert.java | 3 +
.../org/apache/calcite/test/RexProgramTest.java | 128 +++++++++-
.../adapter/druid/DruidConnectionImpl.java | 2 +-
.../adapter/druid/DruidDateTimeUtils.java | 74 +++---
.../calcite/adapter/druid/DruidQuery.java | 19 +-
.../calcite/adapter/druid/DruidRules.java | 6 +-
.../adapter/druid/DruidTableFactory.java | 2 +-
.../druid/TimeExtractionDimensionSpec.java | 14 +-
.../adapter/druid/TimeExtractionFunction.java | 21 +-
.../adapter/druid/DruidQueryFilterTest.java | 2 +-
.../org/apache/calcite/test/DruidAdapterIT.java | 252 +++++++++----------
.../calcite/test/DruidDateRangeRulesTest.java | 4 +-
site/_docs/reference.md | 9 +-
38 files changed, 1361 insertions(+), 258 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/calcite/blob/939c9a62/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java
index 0c1f542..0b3aa84 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java
@@ -1655,7 +1655,14 @@ public class RexImpTable {
case 2:
final Type type;
final Method floorMethod;
+ Expression operand = translatedOperands.get(0);
switch (call.getType().getSqlTypeName()) {
+ case TIMESTAMP_WITH_LOCAL_TIME_ZONE:
+ operand = Expressions.call(
+ BuiltInMethod.TIMESTAMP_WITH_LOCAL_TIME_ZONE_TO_TIMESTAMP.method,
+ operand,
+ Expressions.call(BuiltInMethod.TIME_ZONE.method, translator.getRoot()));
+ // fall through
case TIMESTAMP:
type = long.class;
floorMethod = timestampMethod;
@@ -1671,19 +1678,19 @@ public class RexImpTable {
case YEAR:
case MONTH:
return Expressions.call(floorMethod, tur,
- call(translatedOperands, type, TimeUnit.DAY));
+ call(operand, type, TimeUnit.DAY));
default:
- return call(translatedOperands, type, timeUnitRange.startUnit);
+ return call(operand, type, timeUnitRange.startUnit);
}
default:
throw new AssertionError();
}
}
- private Expression call(List<Expression> translatedOperands, Type type,
+ private Expression call(Expression operand, Type type,
TimeUnit timeUnit) {
return Expressions.call(SqlFunctions.class, methodName,
- Types.castIfNecessary(type, translatedOperands.get(0)),
+ Types.castIfNecessary(type, operand),
Types.castIfNecessary(type,
Expressions.constant(timeUnit.multiplier)));
}
http://git-wip-us.apache.org/repos/asf/calcite/blob/939c9a62/core/src/main/java/org/apache/calcite/adapter/enumerable/RexToLixTranslator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexToLixTranslator.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/RexToLixTranslator.java
index 10e969f..270db82 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexToLixTranslator.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/RexToLixTranslator.java
@@ -245,6 +245,14 @@ public class RexToLixTranslator {
Expressions.call(BuiltInMethod.FLOOR_DIV.method,
operand, Expressions.constant(DateTimeUtils.MILLIS_PER_DAY)),
int.class);
+ break;
+ case TIMESTAMP_WITH_LOCAL_TIME_ZONE:
+ convert = RexImpTable.optimize2(
+ operand,
+ Expressions.call(
+ BuiltInMethod.TIMESTAMP_WITH_LOCAL_TIME_ZONE_TO_DATE.method,
+ operand,
+ Expressions.call(BuiltInMethod.TIME_ZONE.method, root)));
}
break;
case TIME:
@@ -254,6 +262,14 @@ public class RexToLixTranslator {
convert =
Expressions.call(BuiltInMethod.STRING_TO_TIME.method, operand);
break;
+ case TIME_WITH_LOCAL_TIME_ZONE:
+ convert = RexImpTable.optimize2(
+ operand,
+ Expressions.call(
+ BuiltInMethod.TIME_WITH_LOCAL_TIME_ZONE_TO_TIME.method,
+ operand,
+ Expressions.call(BuiltInMethod.TIME_ZONE.method, root)));
+ break;
case TIMESTAMP:
convert = Expressions.convert_(
Expressions.call(
@@ -261,6 +277,49 @@ public class RexToLixTranslator {
operand,
Expressions.constant(DateTimeUtils.MILLIS_PER_DAY)),
int.class);
+ break;
+ case TIMESTAMP_WITH_LOCAL_TIME_ZONE:
+ convert = RexImpTable.optimize2(
+ operand,
+ Expressions.call(
+ BuiltInMethod.TIMESTAMP_WITH_LOCAL_TIME_ZONE_TO_TIME.method,
+ operand,
+ Expressions.call(BuiltInMethod.TIME_ZONE.method, root)));
+ }
+ break;
+ case TIME_WITH_LOCAL_TIME_ZONE:
+ switch (sourceType.getSqlTypeName()) {
+ case CHAR:
+ case VARCHAR:
+ convert =
+ Expressions.call(BuiltInMethod.STRING_TO_TIME_WITH_LOCAL_TIME_ZONE.method, operand);
+ break;
+ case TIME:
+ convert = Expressions.call(
+ BuiltInMethod.TIME_STRING_TO_TIME_WITH_LOCAL_TIME_ZONE.method,
+ RexImpTable.optimize2(
+ operand,
+ Expressions.call(
+ BuiltInMethod.UNIX_TIME_TO_STRING.method,
+ operand)),
+ Expressions.call(BuiltInMethod.TIME_ZONE.method, root));
+ break;
+ case TIMESTAMP:
+ convert = Expressions.call(
+ BuiltInMethod.TIMESTAMP_STRING_TO_TIMESTAMP_WITH_LOCAL_TIME_ZONE.method,
+ RexImpTable.optimize2(
+ operand,
+ Expressions.call(
+ BuiltInMethod.UNIX_TIMESTAMP_TO_STRING.method,
+ operand)),
+ Expressions.call(BuiltInMethod.TIME_ZONE.method, root));
+ break;
+ case TIMESTAMP_WITH_LOCAL_TIME_ZONE:
+ convert = RexImpTable.optimize2(
+ operand,
+ Expressions.call(
+ BuiltInMethod.TIMESTAMP_WITH_LOCAL_TIME_ZONE_TO_TIME_WITH_LOCAL_TIME_ZONE.method,
+ operand));
}
break;
case TIMESTAMP:
@@ -285,6 +344,82 @@ public class RexToLixTranslator {
Expressions.constant(DateTimeUtils.MILLIS_PER_DAY)),
Expressions.convert_(operand, long.class));
break;
+ case TIME_WITH_LOCAL_TIME_ZONE:
+ convert = RexImpTable.optimize2(
+ operand,
+ Expressions.call(
+ BuiltInMethod.TIME_WITH_LOCAL_TIME_ZONE_TO_TIMESTAMP.method,
+ Expressions.call(
+ BuiltInMethod.UNIX_DATE_TO_STRING.method,
+ Expressions.call(BuiltInMethod.CURRENT_DATE.method, root)),
+ operand,
+ Expressions.call(BuiltInMethod.TIME_ZONE.method, root)));
+ break;
+ case TIMESTAMP_WITH_LOCAL_TIME_ZONE:
+ convert = RexImpTable.optimize2(
+ operand,
+ Expressions.call(
+ BuiltInMethod.TIMESTAMP_WITH_LOCAL_TIME_ZONE_TO_TIMESTAMP.method,
+ operand,
+ Expressions.call(BuiltInMethod.TIME_ZONE.method, root)));
+ }
+ break;
+ case TIMESTAMP_WITH_LOCAL_TIME_ZONE:
+ switch (sourceType.getSqlTypeName()) {
+ case CHAR:
+ case VARCHAR:
+ convert =
+ Expressions.call(
+ BuiltInMethod.STRING_TO_TIMESTAMP_WITH_LOCAL_TIME_ZONE.method,
+ operand);
+ break;
+ case DATE:
+ convert = Expressions.call(
+ BuiltInMethod.TIMESTAMP_STRING_TO_TIMESTAMP_WITH_LOCAL_TIME_ZONE.method,
+ RexImpTable.optimize2(
+ operand,
+ Expressions.call(
+ BuiltInMethod.UNIX_TIMESTAMP_TO_STRING.method,
+ Expressions.multiply(
+ Expressions.convert_(operand, long.class),
+ Expressions.constant(DateTimeUtils.MILLIS_PER_DAY)))),
+ Expressions.call(BuiltInMethod.TIME_ZONE.method, root));
+ break;
+ case TIME:
+ convert = Expressions.call(
+ BuiltInMethod.TIMESTAMP_STRING_TO_TIMESTAMP_WITH_LOCAL_TIME_ZONE.method,
+ RexImpTable.optimize2(
+ operand,
+ Expressions.call(
+ BuiltInMethod.UNIX_TIMESTAMP_TO_STRING.method,
+ Expressions.add(
+ Expressions.multiply(
+ Expressions.convert_(
+ Expressions.call(BuiltInMethod.CURRENT_DATE.method, root),
+ long.class),
+ Expressions.constant(DateTimeUtils.MILLIS_PER_DAY)),
+ Expressions.convert_(operand, long.class)))),
+ Expressions.call(BuiltInMethod.TIME_ZONE.method, root));
+ break;
+ case TIME_WITH_LOCAL_TIME_ZONE:
+ convert = RexImpTable.optimize2(
+ operand,
+ Expressions.call(
+ BuiltInMethod.TIME_WITH_LOCAL_TIME_ZONE_TO_TIMESTAMP_WITH_LOCAL_TIME_ZONE.method,
+ Expressions.call(
+ BuiltInMethod.UNIX_DATE_TO_STRING.method,
+ Expressions.call(BuiltInMethod.CURRENT_DATE.method, root)),
+ operand));
+ break;
+ case TIMESTAMP:
+ convert = Expressions.call(
+ BuiltInMethod.TIMESTAMP_STRING_TO_TIMESTAMP_WITH_LOCAL_TIME_ZONE.method,
+ RexImpTable.optimize2(
+ operand,
+ Expressions.call(
+ BuiltInMethod.UNIX_TIMESTAMP_TO_STRING.method,
+ operand)),
+ Expressions.call(BuiltInMethod.TIME_ZONE.method, root));
}
break;
case BOOLEAN:
@@ -315,6 +450,14 @@ public class RexToLixTranslator {
BuiltInMethod.UNIX_TIME_TO_STRING.method,
operand));
break;
+ case TIME_WITH_LOCAL_TIME_ZONE:
+ convert = RexImpTable.optimize2(
+ operand,
+ Expressions.call(
+ BuiltInMethod.TIME_WITH_LOCAL_TIME_ZONE_TO_STRING.method,
+ operand,
+ Expressions.call(BuiltInMethod.TIME_ZONE.method, root)));
+ break;
case TIMESTAMP:
convert = RexImpTable.optimize2(
operand,
@@ -322,6 +465,14 @@ public class RexToLixTranslator {
BuiltInMethod.UNIX_TIMESTAMP_TO_STRING.method,
operand));
break;
+ case TIMESTAMP_WITH_LOCAL_TIME_ZONE:
+ convert = RexImpTable.optimize2(
+ operand,
+ Expressions.call(
+ BuiltInMethod.TIMESTAMP_WITH_LOCAL_TIME_ZONE_TO_STRING.method,
+ operand,
+ Expressions.call(BuiltInMethod.TIME_ZONE.method, root)));
+ break;
case INTERVAL_YEAR:
case INTERVAL_YEAR_MONTH:
case INTERVAL_MONTH:
@@ -621,6 +772,7 @@ public class RexToLixTranslator {
Expressions.constant(bd.toString()));
case DATE:
case TIME:
+ case TIME_WITH_LOCAL_TIME_ZONE:
case INTERVAL_YEAR:
case INTERVAL_YEAR_MONTH:
case INTERVAL_MONTH:
@@ -628,6 +780,7 @@ public class RexToLixTranslator {
javaClass = int.class;
break;
case TIMESTAMP:
+ case TIMESTAMP_WITH_LOCAL_TIME_ZONE:
case INTERVAL_DAY:
case INTERVAL_DAY_HOUR:
case INTERVAL_DAY_MINUTE:
http://git-wip-us.apache.org/repos/asf/calcite/blob/939c9a62/core/src/main/java/org/apache/calcite/jdbc/JavaTypeFactoryImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/jdbc/JavaTypeFactoryImpl.java b/core/src/main/java/org/apache/calcite/jdbc/JavaTypeFactoryImpl.java
index 2e0ded2..8999f44 100644
--- a/core/src/main/java/org/apache/calcite/jdbc/JavaTypeFactoryImpl.java
+++ b/core/src/main/java/org/apache/calcite/jdbc/JavaTypeFactoryImpl.java
@@ -176,12 +176,14 @@ public class JavaTypeFactoryImpl
return String.class;
case DATE:
case TIME:
+ case TIME_WITH_LOCAL_TIME_ZONE:
case INTEGER:
case INTERVAL_YEAR:
case INTERVAL_YEAR_MONTH:
case INTERVAL_MONTH:
return type.isNullable() ? Integer.class : int.class;
case TIMESTAMP:
+ case TIMESTAMP_WITH_LOCAL_TIME_ZONE:
case BIGINT:
case INTERVAL_DAY:
case INTERVAL_DAY_HOUR:
http://git-wip-us.apache.org/repos/asf/calcite/blob/939c9a62/core/src/main/java/org/apache/calcite/rel/metadata/RelMdSize.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdSize.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdSize.java
index bd12347..085fd7c 100644
--- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdSize.java
+++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdSize.java
@@ -281,6 +281,7 @@ public class RelMdSize implements MetadataHandler<BuiltInMetadata.Size> {
case DECIMAL:
case DATE:
case TIME:
+ case TIME_WITH_LOCAL_TIME_ZONE:
case INTERVAL_YEAR:
case INTERVAL_YEAR_MONTH:
case INTERVAL_MONTH:
@@ -289,6 +290,7 @@ public class RelMdSize implements MetadataHandler<BuiltInMetadata.Size> {
case DOUBLE:
case FLOAT: // sic
case TIMESTAMP:
+ case TIMESTAMP_WITH_LOCAL_TIME_ZONE:
case INTERVAL_DAY:
case INTERVAL_DAY_HOUR:
case INTERVAL_DAY_MINUTE:
@@ -339,6 +341,7 @@ public class RelMdSize implements MetadataHandler<BuiltInMetadata.Size> {
case REAL:
case DATE:
case TIME:
+ case TIME_WITH_LOCAL_TIME_ZONE:
case INTERVAL_YEAR:
case INTERVAL_YEAR_MONTH:
case INTERVAL_MONTH:
@@ -346,6 +349,7 @@ public class RelMdSize implements MetadataHandler<BuiltInMetadata.Size> {
case BIGINT:
case DOUBLE:
case TIMESTAMP:
+ case TIMESTAMP_WITH_LOCAL_TIME_ZONE:
case INTERVAL_DAY:
case INTERVAL_DAY_HOUR:
case INTERVAL_DAY_MINUTE:
http://git-wip-us.apache.org/repos/asf/calcite/blob/939c9a62/core/src/main/java/org/apache/calcite/rel/rules/SortProjectTransposeRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/SortProjectTransposeRule.java b/core/src/main/java/org/apache/calcite/rel/rules/SortProjectTransposeRule.java
index e7b4467..127e95e 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/SortProjectTransposeRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/SortProjectTransposeRule.java
@@ -23,6 +23,7 @@ import org.apache.calcite.plan.RelOptRuleOperand;
import org.apache.calcite.plan.RelOptUtil;
import org.apache.calcite.rel.RelCollation;
import org.apache.calcite.rel.RelCollationTraitDef;
+import org.apache.calcite.rel.RelCollations;
import org.apache.calcite.rel.RelFieldCollation;
import org.apache.calcite.rel.RelNode;
import org.apache.calcite.rel.core.Project;
@@ -102,7 +103,7 @@ public class SortProjectTransposeRule extends RelOptRule {
final RexCall cast = (RexCall) node;
final RexCallBinding binding =
RexCallBinding.create(cluster.getTypeFactory(), cast,
- ImmutableList.of(RexUtil.apply(map, sort.getCollation())));
+ ImmutableList.of(RelCollations.of(RexUtil.apply(map, fc))));
if (cast.getOperator().getMonotonicity(binding) == SqlMonotonicity.NOT_MONOTONIC) {
return;
}
http://git-wip-us.apache.org/repos/asf/calcite/blob/939c9a62/core/src/main/java/org/apache/calcite/rel/type/RelDataTypeSystemImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/type/RelDataTypeSystemImpl.java b/core/src/main/java/org/apache/calcite/rel/type/RelDataTypeSystemImpl.java
index 3e0eebd..b7b8839 100644
--- a/core/src/main/java/org/apache/calcite/rel/type/RelDataTypeSystemImpl.java
+++ b/core/src/main/java/org/apache/calcite/rel/type/RelDataTypeSystemImpl.java
@@ -97,9 +97,11 @@ public abstract class RelDataTypeSystemImpl implements RelDataTypeSystem {
case DOUBLE:
return 15;
case TIME:
+ case TIME_WITH_LOCAL_TIME_ZONE:
case DATE:
return 0; // SQL99 part 2 section 6.1 syntax rule 30
case TIMESTAMP:
+ case TIMESTAMP_WITH_LOCAL_TIME_ZONE:
// farrago supports only 0 (see
// SqlTypeName.getDefaultPrecision), but it should be 6
// (microseconds) per SQL99 part 2 section 6.1 syntax rule 30.
@@ -120,7 +122,9 @@ public abstract class RelDataTypeSystemImpl implements RelDataTypeSystem {
case BINARY:
return 65536;
case TIME:
+ case TIME_WITH_LOCAL_TIME_ZONE:
case TIMESTAMP:
+ case TIMESTAMP_WITH_LOCAL_TIME_ZONE:
return SqlTypeName.MAX_DATETIME_PRECISION;
case INTERVAL_YEAR:
case INTERVAL_YEAR_MONTH:
@@ -159,6 +163,8 @@ public abstract class RelDataTypeSystemImpl implements RelDataTypeSystem {
return isPrefix ? "x'" : "'";
case TIMESTAMP:
return isPrefix ? "TIMESTAMP '" : "'";
+ case TIMESTAMP_WITH_LOCAL_TIME_ZONE:
+ return isPrefix ? "TIMESTAMP WITH LOCAL TIME ZONE '" : "'";
case INTERVAL_DAY:
case INTERVAL_DAY_HOUR:
case INTERVAL_DAY_MINUTE:
@@ -176,6 +182,8 @@ public abstract class RelDataTypeSystemImpl implements RelDataTypeSystem {
return isPrefix ? "INTERVAL '" : "' YEAR TO MONTH";
case TIME:
return isPrefix ? "TIME '" : "'";
+ case TIME_WITH_LOCAL_TIME_ZONE:
+ return isPrefix ? "TIME WITH LOCAL TIME ZONE '" : "'";
case DATE:
return isPrefix ? "DATE '" : "'";
case ARRAY:
http://git-wip-us.apache.org/repos/asf/calcite/blob/939c9a62/core/src/main/java/org/apache/calcite/rex/RexBuilder.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rex/RexBuilder.java b/core/src/main/java/org/apache/calcite/rex/RexBuilder.java
index adf7fee..2144ab8 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexBuilder.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexBuilder.java
@@ -863,6 +863,14 @@ public class RexBuilder {
}
o = ((TimeString) o).round(p);
break;
+ case TIME_WITH_LOCAL_TIME_ZONE:
+ assert o instanceof TimeString;
+ p = type.getPrecision();
+ if (p == RelDataType.PRECISION_NOT_SPECIFIED) {
+ p = 0;
+ }
+ o = ((TimeString) o).round(p);
+ break;
case TIMESTAMP:
assert o instanceof TimestampString;
p = type.getPrecision();
@@ -871,6 +879,13 @@ public class RexBuilder {
}
o = ((TimestampString) o).round(p);
break;
+ case TIMESTAMP_WITH_LOCAL_TIME_ZONE:
+ assert o instanceof TimestampString;
+ p = type.getPrecision();
+ if (p == RelDataType.PRECISION_NOT_SPECIFIED) {
+ p = 0;
+ }
+ o = ((TimestampString) o).round(p);
}
return new RexLiteral(o, type, typeName);
}
@@ -1084,6 +1099,17 @@ public class RexBuilder {
SqlTypeName.TIME);
}
+ /**
+ * Creates a Time with local time-zone literal.
+ */
+ public RexLiteral makeTimeWithLocalTimeZoneLiteral(
+ TimeString time,
+ int precision) {
+ return makeLiteral(Preconditions.checkNotNull(time),
+ typeFactory.createSqlType(SqlTypeName.TIME_WITH_LOCAL_TIME_ZONE, precision),
+ SqlTypeName.TIME_WITH_LOCAL_TIME_ZONE);
+ }
+
/** @deprecated Use {@link #makeTimestampLiteral(TimestampString, int)}. */
@Deprecated // to be removed before 2.0
public RexLiteral makeTimestampLiteral(Calendar calendar, int precision) {
@@ -1102,6 +1128,17 @@ public class RexBuilder {
}
/**
+ * Creates a Timestamp with local time-zone literal.
+ */
+ public RexLiteral makeTimestampWithLocalTimeZoneLiteral(
+ TimestampString timestamp,
+ int precision) {
+ return makeLiteral(Preconditions.checkNotNull(timestamp),
+ typeFactory.createSqlType(SqlTypeName.TIMESTAMP_WITH_LOCAL_TIME_ZONE, precision),
+ SqlTypeName.TIMESTAMP_WITH_LOCAL_TIME_ZONE);
+ }
+
+ /**
* Creates a literal representing an interval type, for example
* {@code YEAR TO MONTH} or {@code DOW}.
*/
@@ -1225,6 +1262,10 @@ public class RexBuilder {
case DATE:
case TIMESTAMP:
return DateTimeUtils.ZERO_CALENDAR;
+ case TIME_WITH_LOCAL_TIME_ZONE:
+ return new TimeString(0, 0, 0);
+ case TIMESTAMP_WITH_LOCAL_TIME_ZONE:
+ return new TimestampString(0, 0, 0, 0, 0, 0);
default:
throw Util.unexpected(type.getSqlTypeName());
}
@@ -1288,10 +1329,14 @@ public class RexBuilder {
return (Boolean) value ? booleanTrue : booleanFalse;
case TIME:
return makeTimeLiteral((TimeString) value, type.getPrecision());
+ case TIME_WITH_LOCAL_TIME_ZONE:
+ return makeTimeWithLocalTimeZoneLiteral((TimeString) value, type.getPrecision());
case DATE:
return makeDateLiteral((DateString) value);
case TIMESTAMP:
return makeTimestampLiteral((TimestampString) value, type.getPrecision());
+ case TIMESTAMP_WITH_LOCAL_TIME_ZONE:
+ return makeTimestampWithLocalTimeZoneLiteral((TimestampString) value, type.getPrecision());
case INTERVAL_YEAR:
case INTERVAL_YEAR_MONTH:
case INTERVAL_MONTH:
@@ -1423,6 +1468,12 @@ public class RexBuilder {
} else {
return TimeString.fromMillisOfDay((Integer) o);
}
+ case TIME_WITH_LOCAL_TIME_ZONE:
+ if (o instanceof TimeString) {
+ return o;
+ } else {
+ return TimeString.fromMillisOfDay((Integer) o);
+ }
case DATE:
if (o instanceof DateString) {
return o;
@@ -1445,6 +1496,12 @@ public class RexBuilder {
} else {
return TimestampString.fromMillisSinceEpoch((Long) o);
}
+ case TIMESTAMP_WITH_LOCAL_TIME_ZONE:
+ if (o instanceof TimestampString) {
+ return o;
+ } else {
+ return TimestampString.fromMillisSinceEpoch((Long) o);
+ }
default:
return o;
}
http://git-wip-us.apache.org/repos/asf/calcite/blob/939c9a62/core/src/main/java/org/apache/calcite/rex/RexLiteral.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rex/RexLiteral.java b/core/src/main/java/org/apache/calcite/rex/RexLiteral.java
index 8c4c732..a5ed918 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexLiteral.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexLiteral.java
@@ -255,8 +255,12 @@ public class RexLiteral extends RexNode {
return value instanceof DateString;
case TIME:
return value instanceof TimeString;
+ case TIME_WITH_LOCAL_TIME_ZONE:
+ return value instanceof TimeString;
case TIMESTAMP:
return value instanceof TimestampString;
+ case TIMESTAMP_WITH_LOCAL_TIME_ZONE:
+ return value instanceof TimestampString;
case INTERVAL_YEAR:
case INTERVAL_YEAR_MONTH:
case INTERVAL_MONTH:
@@ -498,10 +502,18 @@ public class RexLiteral extends RexNode {
assert value instanceof TimeString;
pw.print(value);
break;
+ case TIME_WITH_LOCAL_TIME_ZONE:
+ assert value instanceof TimeString;
+ pw.print(value);
+ break;
case TIMESTAMP:
assert value instanceof TimestampString;
pw.print(value);
break;
+ case TIMESTAMP_WITH_LOCAL_TIME_ZONE:
+ assert value instanceof TimestampString;
+ pw.print(value);
+ break;
case INTERVAL_YEAR:
case INTERVAL_YEAR_MONTH:
case INTERVAL_MONTH:
@@ -724,9 +736,11 @@ public class RexLiteral extends RexNode {
return getValueAs(String.class);
case DECIMAL:
case TIMESTAMP:
+ case TIMESTAMP_WITH_LOCAL_TIME_ZONE:
return getValueAs(Long.class);
case DATE:
case TIME:
+ case TIME_WITH_LOCAL_TIME_ZONE:
return getValueAs(Integer.class);
default:
return value;
@@ -835,6 +849,12 @@ public class RexLiteral extends RexNode {
return clazz.cast(((TimeString) value).toCalendar());
}
break;
+ case TIME_WITH_LOCAL_TIME_ZONE:
+ if (clazz == Integer.class) {
+ // Milliseconds since 1970-01-01 00:00:00
+ return clazz.cast(((TimeString) value).getMillisOfDay());
+ }
+ break;
case TIMESTAMP:
if (clazz == Long.class) {
// Milliseconds since 1970-01-01 00:00:00
@@ -844,6 +864,12 @@ public class RexLiteral extends RexNode {
return clazz.cast(((TimestampString) value).toCalendar());
}
break;
+ case TIMESTAMP_WITH_LOCAL_TIME_ZONE:
+ if (clazz == Long.class) {
+ // Milliseconds since 1970-01-01 00:00:00
+ return clazz.cast(((TimestampString) value).getMillisSinceEpoch());
+ }
+ break;
case INTERVAL_YEAR:
case INTERVAL_YEAR_MONTH:
case INTERVAL_MONTH:
http://git-wip-us.apache.org/repos/asf/calcite/blob/939c9a62/core/src/main/java/org/apache/calcite/rex/RexSimplify.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rex/RexSimplify.java b/core/src/main/java/org/apache/calcite/rex/RexSimplify.java
index 67ac1b8..52c4795 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexSimplify.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexSimplify.java
@@ -811,6 +811,7 @@ public class RexSimplify {
case TIMESTAMP:
return e;
}
+ break;
}
final List<RexNode> reducedValues = new ArrayList<>();
executor.reduce(rexBuilder, ImmutableList.<RexNode>of(e), reducedValues);
http://git-wip-us.apache.org/repos/asf/calcite/blob/939c9a62/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java b/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java
index 6832ee4..736034c 100644
--- a/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java
+++ b/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java
@@ -33,6 +33,8 @@ import org.apache.calcite.linq4j.tree.Primitive;
import org.apache.calcite.runtime.FlatLists.ComparableList;
import org.apache.calcite.util.Bug;
import org.apache.calcite.util.NumberUtil;
+import org.apache.calcite.util.TimeWithTimeZoneString;
+import org.apache.calcite.util.TimestampWithTimeZoneString;
import java.math.BigDecimal;
import java.math.BigInteger;
@@ -1695,6 +1697,50 @@ public class SqlFunctions {
return v == null ? null : internalToTime(v.intValue());
}
+ public static Integer toTimeWithLocalTimeZone(String v) {
+ return v == null ? null : new TimeWithTimeZoneString(v)
+ .withTimeZone(DateTimeUtils.UTC_ZONE)
+ .getLocalTimeString()
+ .getMillisOfDay();
+ }
+
+ public static Integer toTimeWithLocalTimeZone(String v, TimeZone timeZone) {
+ return v == null ? null : new TimeWithTimeZoneString(v + " " + timeZone.getID())
+ .withTimeZone(DateTimeUtils.UTC_ZONE)
+ .getLocalTimeString()
+ .getMillisOfDay();
+ }
+
+ public static int timeWithLocalTimeZoneToTime(int v, TimeZone timeZone) {
+ return TimeWithTimeZoneString.fromMillisOfDay(v)
+ .withTimeZone(timeZone)
+ .getLocalTimeString()
+ .getMillisOfDay();
+ }
+
+ public static long timeWithLocalTimeZoneToTimestamp(String date, int v, TimeZone timeZone) {
+ final TimeWithTimeZoneString tTZ = TimeWithTimeZoneString.fromMillisOfDay(v)
+ .withTimeZone(DateTimeUtils.UTC_ZONE);
+ return new TimestampWithTimeZoneString(date + " " + tTZ.toString())
+ .withTimeZone(timeZone)
+ .getLocalTimestampString()
+ .getMillisSinceEpoch();
+ }
+
+ public static long timeWithLocalTimeZoneToTimestampWithLocalTimeZone(String date, int v) {
+ final TimeWithTimeZoneString tTZ = TimeWithTimeZoneString.fromMillisOfDay(v)
+ .withTimeZone(DateTimeUtils.UTC_ZONE);
+ return new TimestampWithTimeZoneString(date + " " + tTZ.toString())
+ .getLocalTimestampString()
+ .getMillisSinceEpoch();
+ }
+
+ public static String timeWithLocalTimeZoneToString(int v, TimeZone timeZone) {
+ return TimeWithTimeZoneString.fromMillisOfDay(v)
+ .withTimeZone(timeZone)
+ .toString();
+ }
+
/** Converts the internal representation of a SQL TIMESTAMP (long) to the Java
* type used for UDF parameters ({@link java.sql.Timestamp}). */
public static java.sql.Timestamp internalToTimestamp(long v) {
@@ -1705,6 +1751,53 @@ public class SqlFunctions {
return v == null ? null : internalToTimestamp(v.longValue());
}
+ public static int timestampWithLocalTimeZoneToDate(long v, TimeZone timeZone) {
+ return TimestampWithTimeZoneString.fromMillisSinceEpoch(v)
+ .withTimeZone(timeZone)
+ .getLocalDateString()
+ .getDaysSinceEpoch();
+ }
+
+ public static int timestampWithLocalTimeZoneToTime(long v, TimeZone timeZone) {
+ return TimestampWithTimeZoneString.fromMillisSinceEpoch(v)
+ .withTimeZone(timeZone)
+ .getLocalTimeString()
+ .getMillisOfDay();
+ }
+
+ public static long timestampWithLocalTimeZoneToTimestamp(long v, TimeZone timeZone) {
+ return TimestampWithTimeZoneString.fromMillisSinceEpoch(v)
+ .withTimeZone(timeZone)
+ .getLocalTimestampString()
+ .getMillisSinceEpoch();
+ }
+
+ public static String timestampWithLocalTimeZoneToString(long v, TimeZone timeZone) {
+ return TimestampWithTimeZoneString.fromMillisSinceEpoch(v)
+ .withTimeZone(timeZone)
+ .toString();
+ }
+
+ public static int timestampWithLocalTimeZoneToTimeWithLocalTimeZone(long v) {
+ return TimestampWithTimeZoneString.fromMillisSinceEpoch(v)
+ .getLocalTimeString()
+ .getMillisOfDay();
+ }
+
+ public static Long toTimestampWithLocalTimeZone(String v) {
+ return v == null ? null : new TimestampWithTimeZoneString(v)
+ .withTimeZone(DateTimeUtils.UTC_ZONE)
+ .getLocalTimestampString()
+ .getMillisSinceEpoch();
+ }
+
+ public static Long toTimestampWithLocalTimeZone(String v, TimeZone timeZone) {
+ return v == null ? null : new TimestampWithTimeZoneString(v + " " + timeZone.getID())
+ .withTimeZone(DateTimeUtils.UTC_ZONE)
+ .getLocalTimestampString()
+ .getMillisSinceEpoch();
+ }
+
// Don't need shortValueOf etc. - Short.valueOf is sufficient.
/** Helper for CAST(... AS VARCHAR(maxLength)). */
@@ -1867,6 +1960,11 @@ public class SqlFunctions {
return (int) (localTimestamp(root) % DateTimeUtils.MILLIS_PER_DAY);
}
+ @NonDeterministic
+ public static TimeZone timeZone(DataContext root) {
+ return (TimeZone) DataContext.Variable.TIME_ZONE.get(root);
+ }
+
/** SQL {@code TRANSLATE(string, search_chars, replacement_chars)}
* function. */
public static String translate3(String s, String search, String replacement) {
http://git-wip-us.apache.org/repos/asf/calcite/blob/939c9a62/core/src/main/java/org/apache/calcite/schema/Schemas.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/schema/Schemas.java b/core/src/main/java/org/apache/calcite/schema/Schemas.java
index edb833a..6466d31 100644
--- a/core/src/main/java/org/apache/calcite/schema/Schemas.java
+++ b/core/src/main/java/org/apache/calcite/schema/Schemas.java
@@ -54,7 +54,6 @@ import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
-import java.util.TimeZone;
/**
* Utility functions for schemas.
@@ -564,8 +563,7 @@ public final class Schemas {
DummyDataContext(CalciteConnection connection, SchemaPlus rootSchema) {
this.connection = connection;
this.rootSchema = rootSchema;
- this.map =
- ImmutableMap.<String, Object>of("timeZone", TimeZone.getDefault());
+ this.map = ImmutableMap.<String, Object>of();
}
public SchemaPlus getRootSchema() {
http://git-wip-us.apache.org/repos/asf/calcite/blob/939c9a62/core/src/main/java/org/apache/calcite/sql/SqlJdbcDataTypeName.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlJdbcDataTypeName.java b/core/src/main/java/org/apache/calcite/sql/SqlJdbcDataTypeName.java
index 90b0597..2f9d974 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlJdbcDataTypeName.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlJdbcDataTypeName.java
@@ -34,7 +34,9 @@ public enum SqlJdbcDataTypeName {
SQL_VARCHAR(SqlTypeName.VARCHAR),
SQL_DATE(SqlTypeName.DATE),
SQL_TIME(SqlTypeName.TIME),
+ SQL_TIME_WITH_LOCAL_TIME_ZONE(SqlTypeName.TIME_WITH_LOCAL_TIME_ZONE),
SQL_TIMESTAMP(SqlTypeName.TIMESTAMP),
+ SQL_TIMESTAMP_WITH_LOCAL_TIME_ZONE(SqlTypeName.TIMESTAMP_WITH_LOCAL_TIME_ZONE),
SQL_DECIMAL(SqlTypeName.DECIMAL),
SQL_NUMERIC(SqlTypeName.DECIMAL),
SQL_BOOLEAN(SqlTypeName.BOOLEAN),
http://git-wip-us.apache.org/repos/asf/calcite/blob/939c9a62/core/src/main/java/org/apache/calcite/sql/type/SqlTypeAssignmentRules.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeAssignmentRules.java b/core/src/main/java/org/apache/calcite/sql/type/SqlTypeAssignmentRules.java
index f77d639..cd46c39 100644
--- a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeAssignmentRules.java
+++ b/core/src/main/java/org/apache/calcite/sql/type/SqlTypeAssignmentRules.java
@@ -158,9 +158,17 @@ public class SqlTypeAssignmentRules {
rule.add(SqlTypeName.TIMESTAMP);
rules.put(SqlTypeName.TIME, rule);
+ // Time with local time-zone is assignable from ...
+ rules.put(SqlTypeName.TIME_WITH_LOCAL_TIME_ZONE,
+ EnumSet.of(SqlTypeName.TIME_WITH_LOCAL_TIME_ZONE));
+
// Timestamp is assignable from ...
rules.put(SqlTypeName.TIMESTAMP, EnumSet.of(SqlTypeName.TIMESTAMP));
+ // Timestamp with local time-zone is assignable from ...
+ rules.put(SqlTypeName.TIMESTAMP_WITH_LOCAL_TIME_ZONE,
+ EnumSet.of(SqlTypeName.TIMESTAMP_WITH_LOCAL_TIME_ZONE));
+
// Geometry is assignable from ...
rules.put(SqlTypeName.GEOMETRY, EnumSet.of(SqlTypeName.GEOMETRY));
@@ -275,6 +283,7 @@ public class SqlTypeAssignmentRules {
rule = new HashSet<>();
rule.add(SqlTypeName.DATE);
rule.add(SqlTypeName.TIMESTAMP);
+ rule.add(SqlTypeName.TIMESTAMP_WITH_LOCAL_TIME_ZONE);
rule.add(SqlTypeName.CHAR);
rule.add(SqlTypeName.VARCHAR);
coerceRules.put(SqlTypeName.DATE, rule);
@@ -282,19 +291,44 @@ public class SqlTypeAssignmentRules {
// Time is castable from ...
rule = new HashSet<>();
rule.add(SqlTypeName.TIME);
+ rule.add(SqlTypeName.TIME_WITH_LOCAL_TIME_ZONE);
rule.add(SqlTypeName.TIMESTAMP);
+ rule.add(SqlTypeName.TIMESTAMP_WITH_LOCAL_TIME_ZONE);
rule.add(SqlTypeName.CHAR);
rule.add(SqlTypeName.VARCHAR);
coerceRules.put(SqlTypeName.TIME, rule);
+ // Time with local time-zone is castable from ...
+ rule = new HashSet<>();
+ rule.add(SqlTypeName.TIME);
+ rule.add(SqlTypeName.TIME_WITH_LOCAL_TIME_ZONE);
+ rule.add(SqlTypeName.TIMESTAMP);
+ rule.add(SqlTypeName.TIMESTAMP_WITH_LOCAL_TIME_ZONE);
+ rule.add(SqlTypeName.CHAR);
+ rule.add(SqlTypeName.VARCHAR);
+ coerceRules.put(SqlTypeName.TIME_WITH_LOCAL_TIME_ZONE, rule);
+
// Timestamp is castable from ...
rule = new HashSet<>();
rule.add(SqlTypeName.TIMESTAMP);
+ rule.add(SqlTypeName.TIMESTAMP_WITH_LOCAL_TIME_ZONE);
rule.add(SqlTypeName.DATE);
rule.add(SqlTypeName.TIME);
+ rule.add(SqlTypeName.TIME_WITH_LOCAL_TIME_ZONE);
rule.add(SqlTypeName.CHAR);
rule.add(SqlTypeName.VARCHAR);
coerceRules.put(SqlTypeName.TIMESTAMP, rule);
+
+ // Timestamp with local time-zone is castable from ...
+ rule = new HashSet<>();
+ rule.add(SqlTypeName.TIMESTAMP);
+ rule.add(SqlTypeName.TIMESTAMP_WITH_LOCAL_TIME_ZONE);
+ rule.add(SqlTypeName.DATE);
+ rule.add(SqlTypeName.TIME);
+ rule.add(SqlTypeName.TIME_WITH_LOCAL_TIME_ZONE);
+ rule.add(SqlTypeName.CHAR);
+ rule.add(SqlTypeName.VARCHAR);
+ coerceRules.put(SqlTypeName.TIMESTAMP_WITH_LOCAL_TIME_ZONE, rule);
}
//~ Methods ----------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/calcite/blob/939c9a62/core/src/main/java/org/apache/calcite/sql/type/SqlTypeFamily.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeFamily.java b/core/src/main/java/org/apache/calcite/sql/type/SqlTypeFamily.java
index e88f96a..af1733b 100644
--- a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeFamily.java
+++ b/core/src/main/java/org/apache/calcite/sql/type/SqlTypeFamily.java
@@ -99,7 +99,9 @@ public enum SqlTypeFamily implements RelDataTypeFamily {
.put(Types.DATE, DATE)
.put(Types.TIME, TIME)
+ .put(Types.TIME_WITH_TIMEZONE, TIME)
.put(Types.TIMESTAMP, TIMESTAMP)
+ .put(Types.TIMESTAMP_WITH_TIMEZONE, TIMESTAMP)
.put(Types.BOOLEAN, BOOLEAN)
.put(ExtraSqlTypes.REF_CURSOR, CURSOR)
@@ -130,9 +132,9 @@ public enum SqlTypeFamily implements RelDataTypeFamily {
case DATE:
return ImmutableList.of(SqlTypeName.DATE);
case TIME:
- return ImmutableList.of(SqlTypeName.TIME);
+ return ImmutableList.of(SqlTypeName.TIME, SqlTypeName.TIME_WITH_LOCAL_TIME_ZONE);
case TIMESTAMP:
- return ImmutableList.of(SqlTypeName.TIMESTAMP);
+ return ImmutableList.of(SqlTypeName.TIMESTAMP, SqlTypeName.TIMESTAMP_WITH_LOCAL_TIME_ZONE);
case BOOLEAN:
return SqlTypeName.BOOLEAN_TYPES;
case INTERVAL_YEAR_MONTH:
http://git-wip-us.apache.org/repos/asf/calcite/blob/939c9a62/core/src/main/java/org/apache/calcite/sql/type/SqlTypeName.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeName.java b/core/src/main/java/org/apache/calcite/sql/type/SqlTypeName.java
index fcae1ec..e56b9cf 100644
--- a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeName.java
+++ b/core/src/main/java/org/apache/calcite/sql/type/SqlTypeName.java
@@ -63,8 +63,12 @@ public enum SqlTypeName {
DATE(PrecScale.NO_NO, false, Types.DATE, SqlTypeFamily.DATE),
TIME(PrecScale.NO_NO | PrecScale.YES_NO, false, Types.TIME,
SqlTypeFamily.TIME),
+ TIME_WITH_LOCAL_TIME_ZONE(PrecScale.NO_NO | PrecScale.YES_NO, false, Types.OTHER,
+ SqlTypeFamily.TIME),
TIMESTAMP(PrecScale.NO_NO | PrecScale.YES_NO, false, Types.TIMESTAMP,
SqlTypeFamily.TIMESTAMP),
+ TIMESTAMP_WITH_LOCAL_TIME_ZONE(PrecScale.NO_NO | PrecScale.YES_NO, false, Types.OTHER,
+ SqlTypeFamily.TIMESTAMP),
INTERVAL_YEAR(PrecScale.NO_NO, false, Types.OTHER,
SqlTypeFamily.INTERVAL_YEAR_MONTH),
INTERVAL_YEAR_MONTH(PrecScale.NO_NO, false, Types.OTHER,
@@ -147,7 +151,7 @@ public enum SqlTypeName {
INTERVAL_DAY, INTERVAL_DAY_HOUR, INTERVAL_DAY_MINUTE,
INTERVAL_DAY_SECOND, INTERVAL_HOUR, INTERVAL_HOUR_MINUTE,
INTERVAL_HOUR_SECOND, INTERVAL_MINUTE, INTERVAL_MINUTE_SECOND,
- INTERVAL_SECOND,
+ INTERVAL_SECOND, TIME_WITH_LOCAL_TIME_ZONE, TIMESTAMP_WITH_LOCAL_TIME_ZONE,
FLOAT, MULTISET, DISTINCT, STRUCTURED, ROW, CURSOR, COLUMN_LIST);
public static final List<SqlTypeName> BOOLEAN_TYPES =
@@ -178,7 +182,8 @@ public enum SqlTypeName {
combine(CHAR_TYPES, BINARY_TYPES);
public static final List<SqlTypeName> DATETIME_TYPES =
- ImmutableList.of(DATE, TIME, TIMESTAMP);
+ ImmutableList.of(DATE, TIME, TIME_WITH_LOCAL_TIME_ZONE,
+ TIMESTAMP, TIMESTAMP_WITH_LOCAL_TIME_ZONE);
public static final Set<SqlTypeName> YEAR_INTERVAL_TYPES =
Sets.immutableEnumSet(SqlTypeName.INTERVAL_YEAR,
@@ -740,7 +745,9 @@ public enum SqlTypeName {
case VARBINARY:
case BINARY:
case TIME:
+ case TIME_WITH_LOCAL_TIME_ZONE:
case TIMESTAMP:
+ case TIMESTAMP_WITH_LOCAL_TIME_ZONE:
return 1;
case INTERVAL_YEAR:
case INTERVAL_YEAR_MONTH:
http://git-wip-us.apache.org/repos/asf/calcite/blob/939c9a62/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java b/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java
index 8940629..14bff94 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java
@@ -678,6 +678,14 @@ public class StandardConvertletTable extends ReflectiveConvertletTable {
case INTERVAL_MINUTE_SECOND:
case INTERVAL_SECOND:
break;
+ case TIMESTAMP_WITH_LOCAL_TIME_ZONE:
+ RelDataType type =
+ cx.getTypeFactory().createSqlType(SqlTypeName.TIMESTAMP);
+ type = cx.getTypeFactory().createTypeWithNullability(
+ type,
+ exprs.get(1).getType().isNullable());
+ res = rexBuilder.makeCast(type, res);
+ // fall through
case TIMESTAMP:
res = divide(rexBuilder, res, TimeUnit.DAY.multiplier);
// fall through
@@ -690,6 +698,14 @@ public class StandardConvertletTable extends ReflectiveConvertletTable {
break;
case DECADE:
switch (sqlTypeName) {
+ case TIMESTAMP_WITH_LOCAL_TIME_ZONE:
+ RelDataType type =
+ cx.getTypeFactory().createSqlType(SqlTypeName.TIMESTAMP);
+ type = cx.getTypeFactory().createTypeWithNullability(
+ type,
+ exprs.get(1).getType().isNullable());
+ res = rexBuilder.makeCast(type, res);
+ // fall through
case TIMESTAMP:
res = divide(rexBuilder, res, TimeUnit.DAY.multiplier);
// fall through
@@ -709,6 +725,16 @@ public class StandardConvertletTable extends ReflectiveConvertletTable {
case TIMESTAMP:
// convert to seconds
return divide(rexBuilder, res, TimeUnit.SECOND.multiplier);
+ case TIMESTAMP_WITH_LOCAL_TIME_ZONE:
+ RelDataType type =
+ cx.getTypeFactory().createSqlType(SqlTypeName.TIMESTAMP);
+ type = cx.getTypeFactory().createTypeWithNullability(
+ type,
+ exprs.get(1).getType().isNullable());
+ return divide(
+ rexBuilder,
+ rexBuilder.makeCast(type, res),
+ TimeUnit.SECOND.multiplier);
case INTERVAL_YEAR:
case INTERVAL_YEAR_MONTH:
case INTERVAL_MONTH:
http://git-wip-us.apache.org/repos/asf/calcite/blob/939c9a62/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java b/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java
index 3265db5..648f1b0 100644
--- a/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java
+++ b/core/src/main/java/org/apache/calcite/util/BuiltInMethod.java
@@ -297,8 +297,33 @@ public enum BuiltInMethod {
INTERNAL_TO_TIMESTAMP(SqlFunctions.class, "internalToTimestamp", long.class),
STRING_TO_DATE(DateTimeUtils.class, "dateStringToUnixDate", String.class),
STRING_TO_TIME(DateTimeUtils.class, "timeStringToUnixDate", String.class),
- STRING_TO_TIMESTAMP(DateTimeUtils.class, "timestampStringToUnixDate",
+ STRING_TO_TIMESTAMP(DateTimeUtils.class, "timestampStringToUnixDate", String.class),
+ STRING_TO_TIME_WITH_LOCAL_TIME_ZONE(SqlFunctions.class, "toTimeWithLocalTimeZone",
String.class),
+ TIME_STRING_TO_TIME_WITH_LOCAL_TIME_ZONE(SqlFunctions.class, "toTimeWithLocalTimeZone",
+ String.class, TimeZone.class),
+ STRING_TO_TIMESTAMP_WITH_LOCAL_TIME_ZONE(SqlFunctions.class, "toTimestampWithLocalTimeZone",
+ String.class),
+ TIMESTAMP_STRING_TO_TIMESTAMP_WITH_LOCAL_TIME_ZONE(SqlFunctions.class,
+ "toTimestampWithLocalTimeZone", String.class, TimeZone.class),
+ TIME_WITH_LOCAL_TIME_ZONE_TO_TIME(SqlFunctions.class, "timeWithLocalTimeZoneToTime",
+ int.class, TimeZone.class),
+ TIME_WITH_LOCAL_TIME_ZONE_TO_TIMESTAMP(SqlFunctions.class, "timeWithLocalTimeZoneToTimestamp",
+ String.class, int.class, TimeZone.class),
+ TIME_WITH_LOCAL_TIME_ZONE_TO_TIMESTAMP_WITH_LOCAL_TIME_ZONE(SqlFunctions.class,
+ "timeWithLocalTimeZoneToTimestampWithLocalTimeZone", String.class, int.class),
+ TIME_WITH_LOCAL_TIME_ZONE_TO_STRING(SqlFunctions.class, "timeWithLocalTimeZoneToString",
+ int.class, TimeZone.class),
+ TIMESTAMP_WITH_LOCAL_TIME_ZONE_TO_DATE(SqlFunctions.class, "timestampWithLocalTimeZoneToDate",
+ long.class, TimeZone.class),
+ TIMESTAMP_WITH_LOCAL_TIME_ZONE_TO_TIME(SqlFunctions.class, "timestampWithLocalTimeZoneToTime",
+ long.class, TimeZone.class),
+ TIMESTAMP_WITH_LOCAL_TIME_ZONE_TO_TIME_WITH_LOCAL_TIME_ZONE(SqlFunctions.class,
+ "timestampWithLocalTimeZoneToTimeWithLocalTimeZone", long.class),
+ TIMESTAMP_WITH_LOCAL_TIME_ZONE_TO_TIMESTAMP(SqlFunctions.class,
+ "timestampWithLocalTimeZoneToTimestamp", long.class, TimeZone.class),
+ TIMESTAMP_WITH_LOCAL_TIME_ZONE_TO_STRING(SqlFunctions.class,
+ "timestampWithLocalTimeZoneToString", long.class, TimeZone.class),
UNIX_DATE_TO_STRING(DateTimeUtils.class, "unixDateToString", int.class),
UNIX_TIME_TO_STRING(DateTimeUtils.class, "unixTimeToString", int.class),
UNIX_TIMESTAMP_TO_STRING(DateTimeUtils.class, "unixTimestampToString",
@@ -322,6 +347,7 @@ public enum BuiltInMethod {
CURRENT_DATE(SqlFunctions.class, "currentDate", DataContext.class),
LOCAL_TIMESTAMP(SqlFunctions.class, "localTimestamp", DataContext.class),
LOCAL_TIME(SqlFunctions.class, "localTime", DataContext.class),
+ TIME_ZONE(SqlFunctions.class, "timeZone", DataContext.class),
BOOLEAN_TO_STRING(SqlFunctions.class, "toString", boolean.class),
JDBC_ARRAY_TO_LIST(SqlFunctions.class, "arrayToList", java.sql.Array.class),
OBJECT_TO_STRING(Object.class, "toString"),
http://git-wip-us.apache.org/repos/asf/calcite/blob/939c9a62/core/src/main/java/org/apache/calcite/util/DateString.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/util/DateString.java b/core/src/main/java/org/apache/calcite/util/DateString.java
index cea9df3..5aaa1b8 100644
--- a/core/src/main/java/org/apache/calcite/util/DateString.java
+++ b/core/src/main/java/org/apache/calcite/util/DateString.java
@@ -42,7 +42,7 @@ public class DateString implements Comparable<DateString> {
/** Creates a DateString for year, month, day values. */
public DateString(int year, int month, int day) {
- this(TimestampString.ymd(new StringBuilder(), year, month, day).toString());
+ this(DateTimeStringUtils.ymd(new StringBuilder(), year, month, day).toString());
}
@Override public String toString() {
http://git-wip-us.apache.org/repos/asf/calcite/blob/939c9a62/core/src/main/java/org/apache/calcite/util/DateTimeStringUtils.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/util/DateTimeStringUtils.java b/core/src/main/java/org/apache/calcite/util/DateTimeStringUtils.java
new file mode 100644
index 0000000..c0d38df
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/util/DateTimeStringUtils.java
@@ -0,0 +1,88 @@
+/*
+ * 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.calcite.util;
+
+import java.util.TimeZone;
+
+/**
+ * Utility methods to manipulate String representation of DateTime values.
+ */
+public class DateTimeStringUtils {
+
+ private DateTimeStringUtils() {}
+
+ static String pad(int length, long v) {
+ StringBuilder s = new StringBuilder(Long.toString(v));
+ while (s.length() < length) {
+ s.insert(0, "0");
+ }
+ return s.toString();
+ }
+
+ static StringBuilder hms(StringBuilder b, int h, int m, int s) {
+ int2(b, h);
+ b.append(':');
+ int2(b, m);
+ b.append(':');
+ int2(b, s);
+ return b;
+ }
+
+ static StringBuilder ymdhms(StringBuilder b, int year, int month, int day,
+ int h, int m, int s) {
+ ymd(b, year, month, day);
+ b.append(' ');
+ hms(b, h, m, s);
+ return b;
+ }
+
+ static StringBuilder ymd(StringBuilder b, int year, int month, int day) {
+ int4(b, year);
+ b.append('-');
+ int2(b, month);
+ b.append('-');
+ int2(b, day);
+ return b;
+ }
+
+ private static void int4(StringBuilder buf, int i) {
+ buf.append((char) ('0' + (i / 1000) % 10));
+ buf.append((char) ('0' + (i / 100) % 10));
+ buf.append((char) ('0' + (i / 10) % 10));
+ buf.append((char) ('0' + i % 10));
+ }
+
+ private static void int2(StringBuilder buf, int i) {
+ buf.append((char) ('0' + (i / 10) % 10));
+ buf.append((char) ('0' + i % 10));
+ }
+
+ static boolean isValidTimeZone(final String timeZone) {
+ if (timeZone.equals("GMT")) {
+ return true;
+ } else {
+ String id = TimeZone.getTimeZone(timeZone).getID();
+ if (!id.equals("GMT")) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+}
+
+// End DateTimeStringUtils.java
http://git-wip-us.apache.org/repos/asf/calcite/blob/939c9a62/core/src/main/java/org/apache/calcite/util/TimeString.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/util/TimeString.java b/core/src/main/java/org/apache/calcite/util/TimeString.java
index 75aa96b..ce03d87 100644
--- a/core/src/main/java/org/apache/calcite/util/TimeString.java
+++ b/core/src/main/java/org/apache/calcite/util/TimeString.java
@@ -44,7 +44,7 @@ public class TimeString implements Comparable<TimeString> {
/** Creates a TimeString for hour, minute, second and millisecond values. */
public TimeString(int h, int m, int s) {
- this(TimestampString.hms(new StringBuilder(), h, m, s).toString());
+ this(DateTimeStringUtils.hms(new StringBuilder(), h, m, s).toString());
}
/** Sets the fraction field of a {@code TimeString} to a given number
@@ -55,7 +55,7 @@ public class TimeString implements Comparable<TimeString> {
* yields {@code TIME '1970-01-01 02:03:04.056'}. */
public TimeString withMillis(int millis) {
Preconditions.checkArgument(millis >= 0 && millis < 1000);
- return withFraction(TimestampString.pad(3, millis));
+ return withFraction(DateTimeStringUtils.pad(3, millis));
}
/** Sets the fraction field of a {@code TimeString} to a given number
@@ -66,7 +66,7 @@ public class TimeString implements Comparable<TimeString> {
* yields {@code TIME '1970-01-01 02:03:04.000056789'}. */
public TimeString withNanos(int nanos) {
Preconditions.checkArgument(nanos >= 0 && nanos < 1000000000);
- return withFraction(TimestampString.pad(9, nanos));
+ return withFraction(DateTimeStringUtils.pad(9, nanos));
}
/** Sets the fraction field of a {@code TimeString}.
http://git-wip-us.apache.org/repos/asf/calcite/blob/939c9a62/core/src/main/java/org/apache/calcite/util/TimeWithTimeZoneString.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/util/TimeWithTimeZoneString.java b/core/src/main/java/org/apache/calcite/util/TimeWithTimeZoneString.java
new file mode 100644
index 0000000..6547f06
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/util/TimeWithTimeZoneString.java
@@ -0,0 +1,188 @@
+/*
+ * 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.calcite.util;
+
+import org.apache.calcite.avatica.util.DateTimeUtils;
+
+import com.google.common.base.Preconditions;
+
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Locale;
+import java.util.TimeZone;
+
+/**
+ * Time with time-zone literal.
+ *
+ * <p>Immutable, internally represented as a string (in ISO format),
+ * and can support unlimited precision (milliseconds, nanoseconds).
+ */
+public class TimeWithTimeZoneString implements Comparable<TimeWithTimeZoneString> {
+
+ final TimeString localTime;
+ final TimeZone timeZone;
+ final String v;
+
+ /** Creates a TimeWithTimeZoneString. */
+ public TimeWithTimeZoneString(TimeString localTime, TimeZone timeZone) {
+ this.localTime = localTime;
+ this.timeZone = timeZone;
+ this.v = localTime.toString() + " " + timeZone.getID();
+ }
+
+ /** Creates a TimeWithTimeZoneString. */
+ public TimeWithTimeZoneString(String v) {
+ this.localTime = new TimeString(v.substring(0, 8));
+ String timeZoneString = v.substring(9);
+ Preconditions.checkArgument(DateTimeStringUtils.isValidTimeZone(timeZoneString));
+ this.timeZone = TimeZone.getTimeZone(timeZoneString);
+ this.v = v;
+ }
+
+ /** Creates a TimeWithTimeZoneString for hour, minute, second and millisecond values
+ * in the given time-zone. */
+ public TimeWithTimeZoneString(int h, int m, int s, String timeZone) {
+ this(DateTimeStringUtils.hms(new StringBuilder(), h, m, s).toString() + " " + timeZone);
+ }
+
+ /** Sets the fraction field of a {@code TimeWithTimeZoneString} to a given number
+ * of milliseconds. Nukes the value set via {@link #withNanos}.
+ *
+ * <p>For example,
+ * {@code new TimeWithTimeZoneString(1970, 1, 1, 2, 3, 4, "UTC").withMillis(56)}
+ * yields {@code TIME WITH LOCAL TIME ZONE '1970-01-01 02:03:04.056 UTC'}. */
+ public TimeWithTimeZoneString withMillis(int millis) {
+ Preconditions.checkArgument(millis >= 0 && millis < 1000);
+ return withFraction(DateTimeStringUtils.pad(3, millis));
+ }
+
+ /** Sets the fraction field of a {@code TimeString} to a given number
+ * of nanoseconds. Nukes the value set via {@link #withMillis(int)}.
+ *
+ * <p>For example,
+ * {@code new TimeWithTimeZoneString(1970, 1, 1, 2, 3, 4, "UTC").withNanos(56789)}
+ * yields {@code TIME WITH LOCAL TIME ZONE '1970-01-01 02:03:04.000056789 UTC'}. */
+ public TimeWithTimeZoneString withNanos(int nanos) {
+ Preconditions.checkArgument(nanos >= 0 && nanos < 1000000000);
+ return withFraction(DateTimeStringUtils.pad(9, nanos));
+ }
+
+ /** Sets the fraction field of a {@code TimeWithTimeZoneString}.
+ * The precision is determined by the number of leading zeros.
+ * Trailing zeros are stripped.
+ *
+ * <p>For example,
+ * {@code new TimeWithTimeZoneString(1970, 1, 1, 2, 3, 4, "UTC").withFraction("00506000")}
+ * yields {@code TIME WITH LOCAL TIME ZONE '1970-01-01 02:03:04.00506 UTC'}. */
+ public TimeWithTimeZoneString withFraction(String fraction) {
+ String v = this.v;
+ int i = v.indexOf('.');
+ if (i >= 0) {
+ v = v.substring(0, i);
+ } else {
+ v = v.substring(0, 8);
+ }
+ while (fraction.endsWith("0")) {
+ fraction = fraction.substring(0, fraction.length() - 1);
+ }
+ if (fraction.length() > 0) {
+ v = v + "." + fraction;
+ }
+ v = v + this.v.substring(8); // time-zone
+ return new TimeWithTimeZoneString(v);
+ }
+
+ public TimeWithTimeZoneString withTimeZone(TimeZone timeZone) {
+ if (this.timeZone.equals(timeZone)) {
+ return this;
+ }
+ String localTimeString = localTime.toString();
+ String v;
+ String fraction;
+ int i = localTimeString.indexOf('.');
+ if (i >= 0) {
+ v = localTimeString.substring(0, i);
+ fraction = localTimeString.substring(i + 1);
+ } else {
+ v = localTimeString;
+ fraction = null;
+ }
+ final DateTimeUtils.PrecisionTime pt =
+ DateTimeUtils.parsePrecisionDateTimeLiteral(v,
+ new SimpleDateFormat(DateTimeUtils.TIME_FORMAT_STRING, Locale.ROOT),
+ this.timeZone, -1);
+ pt.getCalendar().setTimeZone(timeZone);
+ if (fraction != null) {
+ return new TimeWithTimeZoneString(
+ pt.getCalendar().get(Calendar.HOUR_OF_DAY),
+ pt.getCalendar().get(Calendar.MINUTE),
+ pt.getCalendar().get(Calendar.SECOND),
+ timeZone.getID())
+ .withFraction(fraction);
+ }
+ return new TimeWithTimeZoneString(
+ pt.getCalendar().get(Calendar.HOUR_OF_DAY),
+ pt.getCalendar().get(Calendar.MINUTE),
+ pt.getCalendar().get(Calendar.SECOND),
+ timeZone.getID());
+ }
+
+ @Override public String toString() {
+ return v;
+ }
+
+ @Override public boolean equals(Object o) {
+ // The value is in canonical form (no trailing zeros).
+ return o == this
+ || o instanceof TimeWithTimeZoneString
+ && ((TimeWithTimeZoneString) o).v.equals(v);
+ }
+
+ @Override public int hashCode() {
+ return v.hashCode();
+ }
+
+ @Override public int compareTo(TimeWithTimeZoneString o) {
+ return v.compareTo(o.v);
+ }
+
+ public TimeWithTimeZoneString round(int precision) {
+ Preconditions.checkArgument(precision >= 0);
+ return new TimeWithTimeZoneString(
+ localTime.round(precision), timeZone);
+ }
+
+ public static TimeWithTimeZoneString fromMillisOfDay(int i) {
+ return new TimeWithTimeZoneString(
+ DateTimeUtils.unixTimeToString(i) + " " + DateTimeUtils.UTC_ZONE.getID())
+ .withMillis((int) DateTimeUtils.floorMod(i, 1000));
+ }
+
+ /** Converts this TimeWithTimeZoneString to a string, truncated or padded with
+ * zeroes to a given precision. */
+ public String toString(int precision) {
+ Preconditions.checkArgument(precision >= 0);
+ return localTime.toString(precision) + " " + timeZone.getID();
+ }
+
+ public TimeString getLocalTimeString() {
+ return localTime;
+ }
+
+}
+
+// End TimeWithTimeZoneString.java
http://git-wip-us.apache.org/repos/asf/calcite/blob/939c9a62/core/src/main/java/org/apache/calcite/util/TimestampString.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/util/TimestampString.java b/core/src/main/java/org/apache/calcite/util/TimestampString.java
index 4e392f0..604d5a4 100644
--- a/core/src/main/java/org/apache/calcite/util/TimestampString.java
+++ b/core/src/main/java/org/apache/calcite/util/TimestampString.java
@@ -47,7 +47,7 @@ public class TimestampString implements Comparable<TimestampString> {
/** Creates a TimestampString for year, month, day, hour, minute, second,
* millisecond values. */
public TimestampString(int year, int month, int day, int h, int m, int s) {
- this(ymdhms(new StringBuilder(), year, month, day, h, m, s).toString());
+ this(DateTimeStringUtils.ymdhms(new StringBuilder(), year, month, day, h, m, s).toString());
}
/** Sets the fraction field of a {@code TimestampString} to a given number
@@ -58,7 +58,7 @@ public class TimestampString implements Comparable<TimestampString> {
* yields {@code TIMESTAMP '1970-01-01 02:03:04.056'}. */
public TimestampString withMillis(int millis) {
Preconditions.checkArgument(millis >= 0 && millis < 1000);
- return withFraction(pad(3, millis));
+ return withFraction(DateTimeStringUtils.pad(3, millis));
}
/** Sets the fraction field of a {@code TimestampString} to a given number
@@ -69,7 +69,7 @@ public class TimestampString implements Comparable<TimestampString> {
* yields {@code TIMESTAMP '1970-01-01 02:03:04.000056789'}. */
public TimestampString withNanos(int nanos) {
Preconditions.checkArgument(nanos >= 0 && nanos < 1000000000);
- return withFraction(pad(9, nanos));
+ return withFraction(DateTimeStringUtils.pad(9, nanos));
}
/** Sets the fraction field of a {@code TimestampString}.
@@ -113,44 +113,6 @@ public class TimestampString implements Comparable<TimestampString> {
return v.compareTo(o.v);
}
- static StringBuilder hms(StringBuilder b, int h, int m, int s) {
- int2(b, h);
- b.append(':');
- int2(b, m);
- b.append(':');
- int2(b, s);
- return b;
- }
-
- static StringBuilder ymdhms(StringBuilder b, int year, int month, int day,
- int h, int m, int s) {
- ymd(b, year, month, day);
- b.append(' ');
- hms(b, h, m, s);
- return b;
- }
-
- static StringBuilder ymd(StringBuilder b, int year, int month, int day) {
- int4(b, year);
- b.append('-');
- int2(b, month);
- b.append('-');
- int2(b, day);
- return b;
- }
-
- private static void int4(StringBuilder buf, int i) {
- buf.append((char) ('0' + (i / 1000) % 10));
- buf.append((char) ('0' + (i / 100) % 10));
- buf.append((char) ('0' + (i / 10) % 10));
- buf.append((char) ('0' + i % 10));
- }
-
- private static void int2(StringBuilder buf, int i) {
- buf.append((char) ('0' + (i / 10) % 10));
- buf.append((char) ('0' + i % 10));
- }
-
/** Creates a TimestampString from a Calendar. */
public static TimestampString fromCalendarFields(Calendar calendar) {
return new TimestampString(
@@ -214,14 +176,6 @@ public class TimestampString implements Comparable<TimestampString> {
.withMillis((int) DateTimeUtils.floorMod(millis, 1000));
}
- static String pad(int length, long v) {
- StringBuilder s = new StringBuilder(Long.toString(v));
- while (s.length() < length) {
- s.insert(0, "0");
- }
- return s.toString();
- }
-
public Calendar toCalendar() {
return Util.calendar(getMillisSinceEpoch());
}
http://git-wip-us.apache.org/repos/asf/calcite/blob/939c9a62/core/src/main/java/org/apache/calcite/util/TimestampWithTimeZoneString.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/util/TimestampWithTimeZoneString.java b/core/src/main/java/org/apache/calcite/util/TimestampWithTimeZoneString.java
new file mode 100644
index 0000000..3f32762
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/util/TimestampWithTimeZoneString.java
@@ -0,0 +1,194 @@
+/*
+ * 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.calcite.util;
+
+import org.apache.calcite.avatica.util.DateTimeUtils;
+
+import com.google.common.base.Preconditions;
+
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Locale;
+import java.util.TimeZone;
+
+/**
+ * Timestamp with time-zone literal.
+ *
+ * <p>Immutable, internally represented as a string (in ISO format),
+ * and can support unlimited precision (milliseconds, nanoseconds).
+ */
+public class TimestampWithTimeZoneString
+ implements Comparable<TimestampWithTimeZoneString> {
+
+ final TimestampString localDateTime;
+ final TimeZone timeZone;
+ final String v;
+
+ /** Creates a TimestampWithTimeZoneString. */
+ public TimestampWithTimeZoneString(TimestampString localDateTime, TimeZone timeZone) {
+ this.localDateTime = localDateTime;
+ this.timeZone = timeZone;
+ this.v = localDateTime.toString() + " " + timeZone.getID();
+ }
+
+ /** Creates a TimestampWithTimeZoneString. */
+ public TimestampWithTimeZoneString(String v) {
+ this.localDateTime = new TimestampString(v.substring(0, v.indexOf(' ', 11)));
+ String timeZoneString = v.substring(v.indexOf(' ', 11) + 1);
+ Preconditions.checkArgument(DateTimeStringUtils.isValidTimeZone(timeZoneString));
+ this.timeZone = TimeZone.getTimeZone(timeZoneString);
+ this.v = v;
+ }
+
+ /** Creates a TimestampWithTimeZoneString for year, month, day, hour, minute, second,
+ * millisecond values in the given time-zone. */
+ public TimestampWithTimeZoneString(int year, int month, int day, int h, int m, int s,
+ String timeZone) {
+ this(DateTimeStringUtils.ymdhms(new StringBuilder(), year, month, day, h, m, s).toString()
+ + " " + timeZone);
+ }
+
+ /** Sets the fraction field of a {@code TimestampWithTimeZoneString} to a given number
+ * of milliseconds. Nukes the value set via {@link #withNanos}.
+ *
+ * <p>For example,
+ * {@code new TimestampWithTimeZoneString(1970, 1, 1, 2, 3, 4, "GMT").withMillis(56)}
+ * yields {@code TIMESTAMP WITH LOCAL TIME ZONE '1970-01-01 02:03:04.056 GMT'}. */
+ public TimestampWithTimeZoneString withMillis(int millis) {
+ Preconditions.checkArgument(millis >= 0 && millis < 1000);
+ return withFraction(DateTimeStringUtils.pad(3, millis));
+ }
+
+ /** Sets the fraction field of a {@code TimestampWithTimeZoneString} to a given number
+ * of nanoseconds. Nukes the value set via {@link #withMillis(int)}.
+ *
+ * <p>For example,
+ * {@code new TimestampWithTimeZoneString(1970, 1, 1, 2, 3, 4, "GMT").withNanos(56789)}
+ * yields {@code TIMESTAMP WITH LOCAL TIME ZONE '1970-01-01 02:03:04.000056789 GMT'}. */
+ public TimestampWithTimeZoneString withNanos(int nanos) {
+ Preconditions.checkArgument(nanos >= 0 && nanos < 1000000000);
+ return withFraction(DateTimeStringUtils.pad(9, nanos));
+ }
+
+ /** Sets the fraction field of a {@code TimestampString}.
+ * The precision is determined by the number of leading zeros.
+ * Trailing zeros are stripped.
+ *
+ * <p>For example, {@code
+ * new TimestampWithTimeZoneString(1970, 1, 1, 2, 3, 4, "GMT").withFraction("00506000")}
+ * yields {@code TIMESTAMP WITH LOCAL TIME ZONE '1970-01-01 02:03:04.00506 GMT'}. */
+ public TimestampWithTimeZoneString withFraction(String fraction) {
+ return new TimestampWithTimeZoneString(
+ localDateTime.withFraction(fraction), timeZone);
+ }
+
+ public TimestampWithTimeZoneString withTimeZone(TimeZone timeZone) {
+ if (this.timeZone.equals(timeZone)) {
+ return this;
+ }
+ String localDateTimeString = localDateTime.toString();
+ String v;
+ String fraction;
+ int i = localDateTimeString.indexOf('.');
+ if (i >= 0) {
+ v = localDateTimeString.substring(0, i);
+ fraction = localDateTimeString.substring(i + 1);
+ } else {
+ v = localDateTimeString;
+ fraction = null;
+ }
+ final DateTimeUtils.PrecisionTime pt =
+ DateTimeUtils.parsePrecisionDateTimeLiteral(v,
+ new SimpleDateFormat(DateTimeUtils.TIMESTAMP_FORMAT_STRING, Locale.ROOT),
+ this.timeZone, -1);
+ pt.getCalendar().setTimeZone(timeZone);
+ if (fraction != null) {
+ return new TimestampWithTimeZoneString(
+ pt.getCalendar().get(Calendar.YEAR),
+ pt.getCalendar().get(Calendar.MONTH) + 1,
+ pt.getCalendar().get(Calendar.DAY_OF_MONTH),
+ pt.getCalendar().get(Calendar.HOUR_OF_DAY),
+ pt.getCalendar().get(Calendar.MINUTE),
+ pt.getCalendar().get(Calendar.SECOND),
+ timeZone.getID())
+ .withFraction(fraction);
+ }
+ return new TimestampWithTimeZoneString(
+ pt.getCalendar().get(Calendar.YEAR),
+ pt.getCalendar().get(Calendar.MONTH) + 1,
+ pt.getCalendar().get(Calendar.DAY_OF_MONTH),
+ pt.getCalendar().get(Calendar.HOUR_OF_DAY),
+ pt.getCalendar().get(Calendar.MINUTE),
+ pt.getCalendar().get(Calendar.SECOND),
+ timeZone.getID());
+ }
+
+ @Override public String toString() {
+ return v;
+ }
+
+ @Override public boolean equals(Object o) {
+ // The value is in canonical form (no trailing zeros).
+ return o == this
+ || o instanceof TimestampWithTimeZoneString
+ && ((TimestampWithTimeZoneString) o).v.equals(v);
+ }
+
+ @Override public int hashCode() {
+ return v.hashCode();
+ }
+
+ @Override public int compareTo(TimestampWithTimeZoneString o) {
+ return v.compareTo(o.v);
+ }
+
+ public TimestampWithTimeZoneString round(int precision) {
+ Preconditions.checkArgument(precision >= 0);
+ return new TimestampWithTimeZoneString(
+ localDateTime.round(precision), timeZone);
+ }
+
+ /** Creates a TimestampWithTimeZoneString that is a given number of milliseconds since
+ * the epoch UTC. */
+ public static TimestampWithTimeZoneString fromMillisSinceEpoch(long millis) {
+ return new TimestampWithTimeZoneString(
+ DateTimeUtils.unixTimestampToString(millis) + " " + DateTimeUtils.UTC_ZONE.getID())
+ .withMillis((int) DateTimeUtils.floorMod(millis, 1000));
+ }
+
+ /** Converts this TimestampWithTimeZoneString to a string, truncated or padded with
+ * zeroes to a given precision. */
+ public String toString(int precision) {
+ Preconditions.checkArgument(precision >= 0);
+ return localDateTime.toString(precision) + " " + timeZone.getID();
+ }
+
+ public DateString getLocalDateString() {
+ return new DateString(localDateTime.toString().substring(0, 10));
+ }
+
+ public TimeString getLocalTimeString() {
+ return new TimeString(localDateTime.toString().substring(11));
+ }
+
+ public TimestampString getLocalTimestampString() {
+ return localDateTime;
+ }
+
+}
+
+// End TimestampWithTimeZoneString.java
http://git-wip-us.apache.org/repos/asf/calcite/blob/939c9a62/core/src/test/java/org/apache/calcite/jdbc/CalciteRemoteDriverTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/jdbc/CalciteRemoteDriverTest.java b/core/src/test/java/org/apache/calcite/jdbc/CalciteRemoteDriverTest.java
index 9dd3019..1e6f1a3 100644
--- a/core/src/test/java/org/apache/calcite/jdbc/CalciteRemoteDriverTest.java
+++ b/core/src/test/java/org/apache/calcite/jdbc/CalciteRemoteDriverTest.java
@@ -274,7 +274,7 @@ public class CalciteRemoteDriverTest {
@Test public void testRemoteTypeInfo() throws Exception {
CalciteAssert.hr().with(REMOTE_CONNECTION_FACTORY)
.metaData(GET_TYPEINFO)
- .returns(CalciteAssert.checkResultCount(is(43)));
+ .returns(CalciteAssert.checkResultCount(is(45)));
}
@Test public void testRemoteTableTypes() throws Exception {
http://git-wip-us.apache.org/repos/asf/calcite/blob/939c9a62/core/src/test/java/org/apache/calcite/rex/RexBuilderTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/rex/RexBuilderTest.java b/core/src/test/java/org/apache/calcite/rex/RexBuilderTest.java
index 0fd99f8..f9a61fc 100644
--- a/core/src/test/java/org/apache/calcite/rex/RexBuilderTest.java
+++ b/core/src/test/java/org/apache/calcite/rex/RexBuilderTest.java
@@ -24,11 +24,13 @@ import org.apache.calcite.sql.type.SqlTypeName;
import org.apache.calcite.util.DateString;
import org.apache.calcite.util.TimeString;
import org.apache.calcite.util.TimestampString;
+import org.apache.calcite.util.TimestampWithTimeZoneString;
import org.apache.calcite.util.Util;
import org.junit.Test;
import java.util.Calendar;
+import java.util.TimeZone;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.core.Is.is;
@@ -176,6 +178,77 @@ public class RexBuilderTest {
assertThat(literal.getValueAs(TimestampString.class), notNullValue());
}
+ /** Tests
+ * {@link RexBuilder#makeTimestampWithLocalTimeZoneLiteral(TimestampWithTimeZoneString, int)}. */
+ @Test public void testTimestampWithLocalTimeZoneLiteral() {
+ final RelDataTypeFactory typeFactory =
+ new SqlTypeFactoryImpl(RelDataTypeSystem.DEFAULT);
+ final RelDataType timestampType =
+ typeFactory.createSqlType(SqlTypeName.TIMESTAMP_WITH_LOCAL_TIME_ZONE);
+ final RelDataType timestampType3 =
+ typeFactory.createSqlType(SqlTypeName.TIMESTAMP_WITH_LOCAL_TIME_ZONE, 3);
+ final RelDataType timestampType9 =
+ typeFactory.createSqlType(SqlTypeName.TIMESTAMP_WITH_LOCAL_TIME_ZONE, 9);
+ final RelDataType timestampType18 =
+ typeFactory.createSqlType(SqlTypeName.TIMESTAMP_WITH_LOCAL_TIME_ZONE, 18);
+ final RexBuilder builder = new RexBuilder(typeFactory);
+
+ // The new way
+ final TimestampWithTimeZoneString ts = new TimestampWithTimeZoneString(
+ 1969, 7, 21, 2, 56, 15, TimeZone.getTimeZone("PST").getID());
+ checkTimestampWithLocalTimeZone(
+ builder.makeLiteral(ts.getLocalTimestampString(), timestampType, false));
+
+ // Now with milliseconds
+ final TimestampWithTimeZoneString ts2 = ts.withMillis(56);
+ assertThat(ts2.toString(), is("1969-07-21 02:56:15.056 PST"));
+ final RexNode literal2 = builder.makeLiteral(
+ ts2.getLocalTimestampString(), timestampType3, false);
+ assertThat(((RexLiteral) literal2).getValue().toString(), is("1969-07-21 02:56:15.056"));
+
+ // Now with nanoseconds
+ final TimestampWithTimeZoneString ts3 = ts.withNanos(56);
+ final RexNode literal3 = builder.makeLiteral(
+ ts3.getLocalTimestampString(), timestampType9, false);
+ assertThat(((RexLiteral) literal3).getValueAs(TimestampString.class)
+ .toString(), is("1969-07-21 02:56:15"));
+ final TimestampWithTimeZoneString ts3b = ts.withNanos(2345678);
+ final RexNode literal3b = builder.makeLiteral(
+ ts3b.getLocalTimestampString(), timestampType9, false);
+ assertThat(((RexLiteral) literal3b).getValueAs(TimestampString.class)
+ .toString(), is("1969-07-21 02:56:15.002"));
+
+ // Now with a very long fraction
+ final TimestampWithTimeZoneString ts4 = ts.withFraction("102030405060708090102");
+ final RexNode literal4 = builder.makeLiteral(
+ ts4.getLocalTimestampString(), timestampType18, false);
+ assertThat(((RexLiteral) literal4).getValueAs(TimestampString.class)
+ .toString(), is("1969-07-21 02:56:15.102"));
+
+ // toString
+ assertThat(ts2.round(1).toString(), is("1969-07-21 02:56:15 PST"));
+ assertThat(ts2.round(2).toString(), is("1969-07-21 02:56:15.05 PST"));
+ assertThat(ts2.round(3).toString(), is("1969-07-21 02:56:15.056 PST"));
+ assertThat(ts2.round(4).toString(), is("1969-07-21 02:56:15.056 PST"));
+
+ assertThat(ts2.toString(6), is("1969-07-21 02:56:15.056000 PST"));
+ assertThat(ts2.toString(1), is("1969-07-21 02:56:15.0 PST"));
+ assertThat(ts2.toString(0), is("1969-07-21 02:56:15 PST"));
+
+ assertThat(ts2.round(0).toString(), is("1969-07-21 02:56:15 PST"));
+ assertThat(ts2.round(0).toString(0), is("1969-07-21 02:56:15 PST"));
+ assertThat(ts2.round(0).toString(1), is("1969-07-21 02:56:15.0 PST"));
+ assertThat(ts2.round(0).toString(2), is("1969-07-21 02:56:15.00 PST"));
+ }
+
+ private void checkTimestampWithLocalTimeZone(RexNode node) {
+ assertThat(node.toString(), is("1969-07-21 02:56:15"));
+ RexLiteral literal = (RexLiteral) node;
+ assertThat(literal.getValue() instanceof TimestampString, is(true));
+ assertThat(literal.getValue2() instanceof Long, is(true));
+ assertThat(literal.getValue3() instanceof Long, is(true));
+ }
+
/** Tests {@link RexBuilder#makeTimeLiteral(TimeString, int)}. */
@Test public void testTimeLiteral() {
final RelDataTypeFactory typeFactory =
http://git-wip-us.apache.org/repos/asf/calcite/blob/939c9a62/core/src/test/java/org/apache/calcite/test/CalciteAssert.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/CalciteAssert.java b/core/src/test/java/org/apache/calcite/test/CalciteAssert.java
index 6db9435..3e6b414 100644
--- a/core/src/test/java/org/apache/calcite/test/CalciteAssert.java
+++ b/core/src/test/java/org/apache/calcite/test/CalciteAssert.java
@@ -548,6 +548,9 @@ public class CalciteAssert {
calciteConnection.getProperties().setProperty(
CalciteConnectionProperty.CREATE_MATERIALIZATIONS.camelName(),
Boolean.toString(materializationsEnabled));
+ calciteConnection.getProperties().setProperty(
+ CalciteConnectionProperty.TIME_ZONE.camelName(),
+ DateTimeUtils.UTC_ZONE.getID());
}
for (Pair<Hook, Function> hook : hooks) {
closer.add(hook.left.addThread(hook.right));