aboutsummaryrefslogtreecommitdiff
path: root/exec/vector
diff options
context:
space:
mode:
authorjiang-wu <jwu@alumni.stanford.edu>2018-05-01 14:48:26 -0700
committerAman Sinha <asinha@maprtech.com>2018-05-11 15:58:36 -0700
commitc1f0adc9276ab8314ce9c5dff2d9c92066c71530 (patch)
tree9d8c13bb25ae76af3b0b2cc6c73fa53ce66dd1ae /exec/vector
parent16659ab30fd9fca5af39edd22aaab36409a50930 (diff)
DRILL-6242 Use java.time.Local{Date|Time|DateTime} for Drill Date, Time, Timestamp types. (#3)
close apache/drill#1247 * DRILL-6242 - Use java.time.Local{Date|Time|DateTime} classes to hold values from corresponding Drill date, time, and timestamp types. Conflicts: exec/java-exec/src/main/java/org/apache/drill/exec/vector/complex/fn/ExtendedJsonOutput.java Fix merge conflicts and check style.
Diffstat (limited to 'exec/vector')
-rw-r--r--exec/vector/src/main/codegen/data/ValueVectorTypes.tdd6
-rw-r--r--exec/vector/src/main/codegen/includes/vv_imports.ftl8
-rw-r--r--exec/vector/src/main/codegen/templates/AbstractFieldReader.java2
-rw-r--r--exec/vector/src/main/codegen/templates/FixedValueVectors.java15
-rw-r--r--exec/vector/src/main/codegen/templates/HolderReaderImpl.java12
-rw-r--r--exec/vector/src/main/codegen/templates/NullReader.java2
-rw-r--r--exec/vector/src/main/codegen/templates/UnionReader.java2
-rw-r--r--exec/vector/src/main/java/org/apache/drill/exec/expr/fn/impl/DateUtility.java107
-rw-r--r--exec/vector/src/main/java/org/apache/drill/exec/util/JsonStringArrayList.java1
-rw-r--r--exec/vector/src/main/java/org/apache/drill/exec/util/JsonStringHashMap.java1
-rw-r--r--exec/vector/src/main/java/org/apache/drill/exec/util/SerializationModule.java75
11 files changed, 196 insertions, 35 deletions
diff --git a/exec/vector/src/main/codegen/data/ValueVectorTypes.tdd b/exec/vector/src/main/codegen/data/ValueVectorTypes.tdd
index f6e1f1d09..d4851ca65 100644
--- a/exec/vector/src/main/codegen/data/ValueVectorTypes.tdd
+++ b/exec/vector/src/main/codegen/data/ValueVectorTypes.tdd
@@ -68,7 +68,7 @@
{ class: "UInt4", valueHolder: "UInt4Holder" },
{ class: "Float4", javaType: "float" , boxedType: "Float", accessorType: "double", accessorCast: "set",
fields: [{name: "value", type: "float"}]},
- { class: "Time", javaType: "int", friendlyType: "DateTime", accessorType: "int" },
+ { class: "Time", javaType: "int", friendlyType: "LocalTime", accessorType: "int" },
{ class: "IntervalYear", javaType: "int", friendlyType: "Period" }
{ class: "Decimal9", maxPrecisionDigits: 9, friendlyType: "BigDecimal",
fields: [{name:"value", type:"int"}, {name: "scale", type: "int", include: false},
@@ -85,8 +85,8 @@
{ class: "BigInt"},
{ class: "UInt8" },
{ class: "Float8", javaType: "double" , boxedType: "Double", fields: [{name: "value", type: "double"}], },
- { class: "Date", javaType: "long", friendlyType: "DateTime", accessorType: "long" },
- { class: "TimeStamp", javaType: "long", friendlyType: "DateTime", accessorType: "long" }
+ { class: "Date", javaType: "long", friendlyType: "LocalDate", accessorType: "long" },
+ { class: "TimeStamp", javaType: "long", friendlyType: "LocalDateTime", accessorType: "long" }
{ class: "Decimal18", maxPrecisionDigits: 18, friendlyType: "BigDecimal",
fields: [{name:"value", type:"long"}, {name: "scale", type: "int", include: false},
{name: "precision", type: "int", include: false}] },
diff --git a/exec/vector/src/main/codegen/includes/vv_imports.ftl b/exec/vector/src/main/codegen/includes/vv_imports.ftl
index 058621c94..34fe9c54c 100644
--- a/exec/vector/src/main/codegen/includes/vv_imports.ftl
+++ b/exec/vector/src/main/codegen/includes/vv_imports.ftl
@@ -65,9 +65,11 @@ import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.ByteBuffer;
-import java.sql.Date;
-import java.sql.Time;
-import java.sql.Timestamp;
+import java.time.LocalDate;
+import java.time.LocalTime;
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
+import java.time.Instant;
import java.math.BigDecimal;
import java.math.BigInteger;
diff --git a/exec/vector/src/main/codegen/templates/AbstractFieldReader.java b/exec/vector/src/main/codegen/templates/AbstractFieldReader.java
index 2ed5a3b6d..4e5856b22 100644
--- a/exec/vector/src/main/codegen/templates/AbstractFieldReader.java
+++ b/exec/vector/src/main/codegen/templates/AbstractFieldReader.java
@@ -43,7 +43,7 @@ abstract class AbstractFieldReader extends AbstractBaseReader implements FieldRe
}
<#list ["Object", "BigDecimal", "Integer", "Long", "Boolean",
- "Character", "DateTime", "Period", "Double", "Float",
+ "Character", "LocalDate", "LocalTime", "LocalDateTime", "Period", "Double", "Float",
"Text", "String", "Byte", "Short", "byte[]"] as friendlyType>
<#assign safeType=friendlyType />
<#if safeType=="byte[]"><#assign safeType="ByteArray" /></#if>
diff --git a/exec/vector/src/main/codegen/templates/FixedValueVectors.java b/exec/vector/src/main/codegen/templates/FixedValueVectors.java
index ddd69253a..68ee33bb0 100644
--- a/exec/vector/src/main/codegen/templates/FixedValueVectors.java
+++ b/exec/vector/src/main/codegen/templates/FixedValueVectors.java
@@ -27,6 +27,7 @@
package org.apache.drill.exec.vector;
<#include "/@includes/vv_imports.ftl" />
+
import org.apache.drill.exec.util.DecimalUtility;
/**
@@ -506,17 +507,13 @@ public final class ${minor.class}Vector extends BaseDataValueVector implements F
@Override
public ${friendlyType} getObject(int index) {
- org.joda.time.DateTime date = new org.joda.time.DateTime(get(index), org.joda.time.DateTimeZone.UTC);
- date = date.withZoneRetainFields(org.joda.time.DateTimeZone.getDefault());
- return date;
+ return LocalDateTime.ofInstant(Instant.ofEpochMilli(get(index)), ZoneOffset.UTC).toLocalDate();
}
<#elseif minor.class == "TimeStamp">
@Override
public ${friendlyType} getObject(int index) {
- org.joda.time.DateTime date = new org.joda.time.DateTime(get(index), org.joda.time.DateTimeZone.UTC);
- date = date.withZoneRetainFields(org.joda.time.DateTimeZone.getDefault());
- return date;
+ return LocalDateTime.ofInstant(Instant.ofEpochMilli(get(index)), ZoneOffset.UTC);
}
<#elseif minor.class == "IntervalYear">
@@ -531,10 +528,8 @@ public final class ${minor.class}Vector extends BaseDataValueVector implements F
<#elseif minor.class == "Time">
@Override
- public DateTime getObject(int index) {
- org.joda.time.DateTime time = new org.joda.time.DateTime(get(index), org.joda.time.DateTimeZone.UTC);
- time = time.withZoneRetainFields(org.joda.time.DateTimeZone.getDefault());
- return time;
+ public ${friendlyType} getObject(int index) {
+ return LocalDateTime.ofInstant(Instant.ofEpochMilli(get(index)), ZoneOffset.UTC).toLocalTime();
}
<#elseif minor.class == "Decimal9" || minor.class == "Decimal18">
diff --git a/exec/vector/src/main/codegen/templates/HolderReaderImpl.java b/exec/vector/src/main/codegen/templates/HolderReaderImpl.java
index 4b7be4fd7..1d17a2839 100644
--- a/exec/vector/src/main/codegen/templates/HolderReaderImpl.java
+++ b/exec/vector/src/main/codegen/templates/HolderReaderImpl.java
@@ -206,6 +206,12 @@ public class ${holderMode}${name}HolderReaderImpl extends AbstractFieldReader {
<#elseif minor.class == "Bit" >
return Boolean.valueOf(holder.value != 0);
+<#elseif minor.class == "Time">
+ return LocalDateTime.ofInstant(Instant.ofEpochMilli(this.holder.value), ZoneOffset.UTC).toLocalTime();
+<#elseif minor.class == "Date">
+ return LocalDateTime.ofInstant(Instant.ofEpochMilli(this.holder.value), ZoneOffset.UTC).toLocalDate();
+<#elseif minor.class == "TimeStamp">
+ return LocalDateTime.ofInstant(Instant.ofEpochMilli(this.holder.value), ZoneOffset.UTC);
<#else>
${friendlyType} value = new ${friendlyType}(this.holder.value);
return value;
@@ -281,6 +287,12 @@ public class ${holderMode}${name}HolderReaderImpl extends AbstractFieldReader {
<#elseif minor.class == "Bit" >
return Boolean.valueOf(holder.value != 0);
+<#elseif minor.class == "Time">
+ return LocalDateTime.ofInstant(Instant.ofEpochMilli(this.holder.value), ZoneOffset.UTC).toLocalTime();
+<#elseif minor.class == "Date">
+ return LocalDateTime.ofInstant(Instant.ofEpochMilli(this.holder.value), ZoneOffset.UTC).toLocalDate();
+<#elseif minor.class == "TimeStamp">
+ return LocalDateTime.ofInstant(Instant.ofEpochMilli(this.holder.value), ZoneOffset.UTC);
<#else>
${friendlyType} value = new ${friendlyType}(this.holder.value);
return value;
diff --git a/exec/vector/src/main/codegen/templates/NullReader.java b/exec/vector/src/main/codegen/templates/NullReader.java
index 4d867baa4..28d48b750 100644
--- a/exec/vector/src/main/codegen/templates/NullReader.java
+++ b/exec/vector/src/main/codegen/templates/NullReader.java
@@ -123,7 +123,7 @@ public class NullReader extends AbstractBaseReader implements FieldReader {
}
<#list ["Object", "BigDecimal", "Integer", "Long", "Boolean",
- "Character", "DateTime", "Period", "Double", "Float",
+ "Character", "LocalDate", "LocalTime", "LocalDateTime", "Period", "Double", "Float",
"Text", "String", "Byte", "Short", "byte[]"] as friendlyType>
<#assign safeType=friendlyType />
<#if safeType=="byte[]"><#assign safeType="ByteArray" /></#if>
diff --git a/exec/vector/src/main/codegen/templates/UnionReader.java b/exec/vector/src/main/codegen/templates/UnionReader.java
index 54276f573..84a2327b7 100644
--- a/exec/vector/src/main/codegen/templates/UnionReader.java
+++ b/exec/vector/src/main/codegen/templates/UnionReader.java
@@ -124,7 +124,7 @@ public class UnionReader extends AbstractFieldReader {
}
<#list ["Object", "BigDecimal", "Integer", "Long", "Boolean",
- "Character", "DateTime", "Period", "Double", "Float",
+ "Character", "LocalDate", "LocalTime", "LocalDateTime", "Period", "Double", "Float",
"Text", "String", "Byte", "Short", "byte[]"] as friendlyType>
<#assign safeType=friendlyType />
<#if safeType=="byte[]"><#assign safeType="ByteArray" /></#if>
diff --git a/exec/vector/src/main/java/org/apache/drill/exec/expr/fn/impl/DateUtility.java b/exec/vector/src/main/java/org/apache/drill/exec/expr/fn/impl/DateUtility.java
index a52c95af9..21a4352fa 100644
--- a/exec/vector/src/main/java/org/apache/drill/exec/expr/fn/impl/DateUtility.java
+++ b/exec/vector/src/main/java/org/apache/drill/exec/expr/fn/impl/DateUtility.java
@@ -17,10 +17,15 @@
*/
package org.apache.drill.exec.expr.fn.impl;
-import org.joda.time.format.DateTimeFormat;
-import org.joda.time.format.DateTimeFormatter;
-import org.joda.time.format.DateTimeFormatterBuilder;
-import org.joda.time.format.DateTimeParser;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.OffsetDateTime;
+import java.time.ZoneOffset;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeFormatterBuilder;
+import java.time.temporal.ChronoField;
+import java.time.temporal.TemporalAccessor;
import com.carrotsearch.hppc.ObjectIntHashMap;
@@ -621,10 +626,14 @@ public class DateUtility {
}
}
- public static final DateTimeFormatter formatDate = DateTimeFormat.forPattern("yyyy-MM-dd");
- public static final DateTimeFormatter formatTimeStamp = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss.SSS");
- public static final DateTimeFormatter formatTimeStampTZ = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss.SSS ZZZ");
- public static final DateTimeFormatter formatTime = DateTimeFormat.forPattern("HH:mm:ss.SSS");
+ public static final DateTimeFormatter formatDate = buildFormatter("yyyy-MM-dd");
+ public static final DateTimeFormatter formatTimeStamp = buildFormatter("yyyy-MM-dd HH:mm:ss.SSS");
+ public static final DateTimeFormatter formatTimeStampTZ = buildFormatter("yyyy-MM-dd HH:mm:ss.SSS VV");
+ public static final DateTimeFormatter formatTime = buildFormatter("HH:mm:ss.SSS");
+
+ public static final DateTimeFormatter isoFormatDate = formatDate;
+ public static final DateTimeFormatter isoFormatTimeStamp= buildFormatter("yyyy-MM-dd'T'HH:mm:ss.SSSXX");
+ public static final DateTimeFormatter isoFormatTime = buildFormatter("HH:mm:ss.SSSXX");
public static DateTimeFormatter dateTimeTZFormat = null;
public static DateTimeFormatter timeFormat = null;
@@ -639,29 +648,95 @@ public class DateUtility {
return timezoneList[index];
}
+ /**
+ * Parse given string into a LocalDate
+ */
+ public static LocalDate parseLocalDate(final String value) {
+ return LocalDate.parse(value, formatDate);
+ }
+
+ /**
+ * Parse given string into a LocalTime
+ */
+ public static LocalTime parseLocalTime(final String value) {
+ return LocalTime.parse(value, formatTime);
+ }
+
+ /**
+ * Parse the given string into a LocalDateTime.
+ */
+ public static LocalDateTime parseLocalDateTime(final String value) {
+ return LocalDateTime.parse(value, formatTimeStamp);
+ }
+
// Returns the date time formatter used to parse date strings
public static DateTimeFormatter getDateTimeFormatter() {
if (dateTimeTZFormat == null) {
- DateTimeFormatter dateFormatter = DateTimeFormat.forPattern("yyyy-MM-dd");
- DateTimeParser optionalTime = DateTimeFormat.forPattern(" HH:mm:ss").getParser();
- DateTimeParser optionalSec = DateTimeFormat.forPattern(".SSS").getParser();
- DateTimeParser optionalZone = DateTimeFormat.forPattern(" ZZZ").getParser();
+ DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
+ DateTimeFormatter optionalTime = DateTimeFormatter.ofPattern(" HH:mm:ss");
+ DateTimeFormatter optionalSec = DateTimeFormatter.ofPattern(".SSS");
+ DateTimeFormatter optionalZone = DateTimeFormatter.ofPattern(" ZZZ");
- dateTimeTZFormat = new DateTimeFormatterBuilder().append(dateFormatter).appendOptional(optionalTime).appendOptional(optionalSec).appendOptional(optionalZone).toFormatter();
+ dateTimeTZFormat = new DateTimeFormatterBuilder().parseLenient()
+ .append(dateFormatter)
+ .appendOptional(optionalTime)
+ .appendOptional(optionalSec)
+ .appendOptional(optionalZone)
+ .toFormatter();
}
return dateTimeTZFormat;
}
+ /**
+ * Best effort parsing of the given value
+ */
+ public static LocalDateTime parseBest(String value) {
+ TemporalAccessor parsed = getDateTimeFormatter().parse(value);
+ LocalDate datePart;
+ LocalTime timePart;
+ ZoneOffset zoneOffset;
+
+ long epochDay = 0, nanoSeconds = 0;
+ int offsetSeconds = 0;
+
+ // get different parsed parts
+ if (parsed.isSupported(ChronoField.EPOCH_DAY)) {
+ epochDay = parsed.getLong(ChronoField.EPOCH_DAY);
+ }
+ if (parsed.isSupported(ChronoField.NANO_OF_DAY)) {
+ nanoSeconds = parsed.getLong(ChronoField.NANO_OF_DAY);
+ }
+ if (parsed.isSupported(ChronoField.OFFSET_SECONDS)) {
+ offsetSeconds = parsed.get(ChronoField.OFFSET_SECONDS);
+ }
+
+ zoneOffset = ZoneOffset.ofTotalSeconds(offsetSeconds);
+ datePart = LocalDate.ofEpochDay(epochDay);
+ timePart = LocalTime.ofNanoOfDay(nanoSeconds);
+
+ return OffsetDateTime.of(datePart, timePart, zoneOffset).toLocalDateTime();
+ }
+
// Returns time formatter used to parse time strings
public static DateTimeFormatter getTimeFormatter() {
if (timeFormat == null) {
- DateTimeFormatter timeFormatter = DateTimeFormat.forPattern("HH:mm:ss");
- DateTimeParser optionalSec = DateTimeFormat.forPattern(".SSS").getParser();
- timeFormat = new DateTimeFormatterBuilder().append(timeFormatter).appendOptional(optionalSec).toFormatter();
+ DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("HH:mm:ss");
+ DateTimeFormatter optionalSec = DateTimeFormatter.ofPattern(".SSS");
+ timeFormat = new DateTimeFormatterBuilder().parseLenient()
+ .append(timeFormatter)
+ .appendOptional(optionalSec)
+ .toFormatter();
}
return timeFormat;
}
+ // return a formatter that is lenient in its parsing of fields. e.g.
+ // if the month specification is "MM", a lenient version of the formatter
+ // will accept a single digit month number as well as the 2-digit month
+ // number.
+ public static DateTimeFormatter buildFormatter(String pattern) {
+ return new DateTimeFormatterBuilder().parseLenient().append(DateTimeFormatter.ofPattern(pattern)).toFormatter();
+ }
}
diff --git a/exec/vector/src/main/java/org/apache/drill/exec/util/JsonStringArrayList.java b/exec/vector/src/main/java/org/apache/drill/exec/util/JsonStringArrayList.java
index 216c5cc73..695befdb8 100644
--- a/exec/vector/src/main/java/org/apache/drill/exec/util/JsonStringArrayList.java
+++ b/exec/vector/src/main/java/org/apache/drill/exec/util/JsonStringArrayList.java
@@ -29,6 +29,7 @@ public class JsonStringArrayList<E> extends ArrayList<E> {
static {
mapper = new ObjectMapper();
+ mapper.registerModule(SerializationModule.getModule());
}
@Override
diff --git a/exec/vector/src/main/java/org/apache/drill/exec/util/JsonStringHashMap.java b/exec/vector/src/main/java/org/apache/drill/exec/util/JsonStringHashMap.java
index e4de6d884..f4352d114 100644
--- a/exec/vector/src/main/java/org/apache/drill/exec/util/JsonStringHashMap.java
+++ b/exec/vector/src/main/java/org/apache/drill/exec/util/JsonStringHashMap.java
@@ -34,6 +34,7 @@ public class JsonStringHashMap<K, V> extends LinkedHashMap<K, V> {
static {
mapper = new ObjectMapper();
+ mapper.registerModule(SerializationModule.getModule());
}
@Override
diff --git a/exec/vector/src/main/java/org/apache/drill/exec/util/SerializationModule.java b/exec/vector/src/main/java/org/apache/drill/exec/util/SerializationModule.java
new file mode 100644
index 000000000..04f4144c8
--- /dev/null
+++ b/exec/vector/src/main/java/org/apache/drill/exec/util/SerializationModule.java
@@ -0,0 +1,75 @@
+/*
+ * 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.drill.exec.util;
+
+import java.io.IOException;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.ZoneOffset;
+import java.time.format.DateTimeFormatter;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.module.SimpleModule;
+
+/**
+ * This helper class holds any custom Jackson serializers used when outputing
+ * the data in JSON format.
+ */
+public class SerializationModule {
+
+ // copied from DateUtility. Added here for inclusion into drill-jdbc-all
+ public static final DateTimeFormatter formatDate = DateTimeFormatter.ofPattern("uuuu-MM-dd")
+ .withZone(ZoneOffset.UTC);
+ public static final DateTimeFormatter formatTimeStamp = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss.SSS")
+ .withZone(ZoneOffset.UTC);
+ public static final DateTimeFormatter formatTime = DateTimeFormatter.ofPattern("HH:mm:ss.SSS")
+ .withZone(ZoneOffset.UTC);
+
+ public static final SimpleModule drillModule = new SimpleModule("DrillModule");
+
+ static {
+ drillModule.addSerializer(LocalTime.class, new JsonSerializer<LocalTime>() {
+ @Override
+ public void serialize(LocalTime value, JsonGenerator gen, SerializerProvider serializers) throws IOException, JsonProcessingException {
+ gen.writeString(formatTime.format(value));
+ }
+ });
+
+ drillModule.addSerializer(LocalDate.class, new JsonSerializer<LocalDate>() {
+ @Override
+ public void serialize(LocalDate value, JsonGenerator gen, SerializerProvider serializers) throws IOException, JsonProcessingException {
+ gen.writeString(formatDate.format(value));
+ }
+ });
+
+ drillModule.addSerializer(LocalDateTime.class, new JsonSerializer<LocalDateTime>() {
+ @Override
+ public void serialize(LocalDateTime value, JsonGenerator gen, SerializerProvider serializers) throws IOException, JsonProcessingException {
+ gen.writeString(formatTimeStamp.format(value));
+ }
+ });
+ }
+
+ public static final SimpleModule getModule() {
+ return drillModule;
+ }
+}