This is an automated email from the ASF dual-hosted git repository.
dzamo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/drill.git
The following commit(s) were added to refs/heads/master by this push:
new 39b565f DRILL-7926: Age Function Fix (#2284)
39b565f is described below
commit 39b565f112122734c080324fdcbef518ced16507
Author: dzamo <[email protected]>
AuthorDate: Sat Aug 14 05:48:27 2021 +0200
DRILL-7926: Age Function Fix (#2284)
* Fix query start time code and Drill timestamp util functions.
* Implement AGE function as a Freemarker template.
* Add tests for the unary form of AGE.
* Use Java Time's LocalDateTime.until to simplify TIMESTAMPDIFF.
* Fix expressions in the test physical plan in age.json.
* Add comments explaining AGE function logic.
Co-authored-by: Oleg Zinoviev <[email protected]>
---
.../DateIntervalFunctionTemplates/AgeFunction.java | 121 +++
...mestampDiff.java => TimestampDiffFunction.java} | 24 +-
.../drill/exec/expr/fn/impl/DateTypeFunctions.java | 1046 ++++++++++----------
.../apache/drill/exec/ops/ContextInformation.java | 19 +-
.../drill/exec/fn/impl/TestDateFunctions.java | 17 +-
.../src/test/resources/functions/date/age.json | 25 +-
6 files changed, 691 insertions(+), 561 deletions(-)
diff --git
a/exec/java-exec/src/main/codegen/templates/DateIntervalFunctionTemplates/AgeFunction.java
b/exec/java-exec/src/main/codegen/templates/DateIntervalFunctionTemplates/AgeFunction.java
new file mode 100644
index 0000000..672311c
--- /dev/null
+++
b/exec/java-exec/src/main/codegen/templates/DateIntervalFunctionTemplates/AgeFunction.java
@@ -0,0 +1,121 @@
+/*
+ * 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.
+ */
+<@pp.dropOutputFile />
+<#assign className="GAge"/>
+
+<@pp.changeOutputFile
name="/org/apache/drill/exec/expr/fn/impl/${className}.java"/>
+
+<#include "/@includes/license.ftl"/>
+
+package org.apache.drill.exec.expr.fn.impl;
+
+import org.apache.drill.exec.expr.DrillSimpleFunc;
+import org.apache.drill.exec.expr.annotations.FunctionTemplate;
+import org.apache.drill.exec.expr.annotations.FunctionTemplate.NullHandling;
+import javax.inject.Inject;
+import org.apache.drill.exec.expr.annotations.Output;
+import org.apache.drill.exec.expr.annotations.Workspace;
+import org.apache.drill.exec.expr.annotations.Param;
+import org.apache.drill.exec.expr.holders.*;
+import org.apache.drill.exec.record.RecordBatch;
+import org.apache.drill.exec.ops.ContextInformation;
+
+/*
+ * This class is generated using freemarker and the ${.template_name} template.
+ */
+
+public class ${className} {
+
+<#list dateIntervalFunc.dates as fromUnit>
+<#list dateIntervalFunc.dates as toUnit>
+
+ /**
+ * Binary form, returns the interval between `right` and `left`.
+ * Note that this function does not count calendar boundary crossings,
+ * e.g. between yesterday 23:00 and today 01:00 is two hours, not one day.
+ * Modeled on the AGE function in PostgreSQL, see
+ * https://www.postgresql.org/docs/current/functions-datetime.html.
+ */
+ @FunctionTemplate(name = "age",
+ scope = FunctionTemplate.FunctionScope.SIMPLE,
+ nulls = FunctionTemplate.NullHandling.NULL_IF_NULL)
+ public static class Age${fromUnit}To${toUnit} implements DrillSimpleFunc {
+
+ @Param ${toUnit}Holder left;
+ @Param ${fromUnit}Holder right;
+ @Output IntervalHolder out;
+
+ public void setup() {
+ }
+
+ public void eval() {
+ java.time.LocalDateTime from =
java.time.Instant.ofEpochMilli(right.value).atZone(java.time.ZoneOffset.UTC).toLocalDateTime();
+ java.time.LocalDateTime to =
java.time.Instant.ofEpochMilli(left.value).atZone(java.time.ZoneOffset.UTC).toLocalDateTime();
+
+ long months = from.until(to, java.time.temporal.ChronoUnit.MONTHS);
+ from = from.plusMonths(months);
+ long days = from.until(to, java.time.temporal.ChronoUnit.DAYS);
+ from = from.plusDays(days);
+ long millis = from.until(to, java.time.temporal.ChronoUnit.MILLIS);
+
+ out.months = (int) months;
+ out.days = (int) days;
+ out.milliseconds = (int) millis;
+ }
+ }
+</#list>
+ /**
+ * Unary form, subtracts `right` from midnight so equivalent to
+ * `select age(current_date, right)`.
+ * Note that this function does not count calendar boundary crossings,
+ * e.g. between yesterday 23:00 and today 01:00 is two hours, not one day.
+ * Modeled on the AGE function in PostgreSQL, see
+ * https://www.postgresql.org/docs/current/functions-datetime.html.
+ */
+ @FunctionTemplate(name = "age",
+ scope = FunctionTemplate.FunctionScope.SIMPLE,
+ nulls = FunctionTemplate.NullHandling.NULL_IF_NULL)
+ public static class Age${fromUnit}ToMidnight implements DrillSimpleFunc {
+
+ @Param ${fromUnit}Holder right;
+ @Workspace java.time.LocalDateTime to;
+ @Output IntervalHolder out;
+ @Inject ContextInformation contextInfo;
+
+ public void setup() {
+ java.time.ZoneId zoneId = contextInfo.getRootFragmentTimeZone();
+ java.time.ZonedDateTime zdtStart =
contextInfo.getQueryStartInstant().atZone(zoneId);
+ to =
zdtStart.truncatedTo(java.time.temporal.ChronoUnit.DAYS).toLocalDateTime();
+ }
+
+ public void eval() {
+ java.time.LocalDateTime from =
java.time.Instant.ofEpochMilli(right.value).atZone(java.time.ZoneOffset.UTC).toLocalDateTime();
+
+ long months = from.until(to, java.time.temporal.ChronoUnit.MONTHS);
+ from = from.plusMonths(months);
+ long days = from.until(to, java.time.temporal.ChronoUnit.DAYS);
+ from = from.plusDays(days);
+ long millis = from.until(to, java.time.temporal.ChronoUnit.MILLIS);
+
+ out.months = (int) months;
+ out.days = (int) days;
+ out.milliseconds = (int) millis;
+ }
+ }
+</#list>
+}
diff --git
a/exec/java-exec/src/main/codegen/templates/DateIntervalFunctionTemplates/TimestampDiff.java
b/exec/java-exec/src/main/codegen/templates/DateIntervalFunctionTemplates/TimestampDiffFunction.java
similarity index 69%
rename from
exec/java-exec/src/main/codegen/templates/DateIntervalFunctionTemplates/TimestampDiff.java
rename to
exec/java-exec/src/main/codegen/templates/DateIntervalFunctionTemplates/TimestampDiffFunction.java
index b139efc..3c5e51d 100644
---
a/exec/java-exec/src/main/codegen/templates/DateIntervalFunctionTemplates/TimestampDiff.java
+++
b/exec/java-exec/src/main/codegen/templates/DateIntervalFunctionTemplates/TimestampDiffFunction.java
@@ -72,25 +72,11 @@ public class ${className} {
<#elseif unit == "Week">
out.value = (right.value - left.value) / 604800000; // 7 * 24 * 60 * 60
* 1000
<#elseif unit == "Month" || unit == "Quarter" || unit == "Year">
- long timeMilliseconds = left.value %
org.apache.drill.exec.vector.DateUtilities.daysToStandardMillis
- - right.value %
org.apache.drill.exec.vector.DateUtilities.daysToStandardMillis;
-
- java.time.Period between = java.time.Period.between(
-
java.time.Instant.ofEpochMilli(left.value).atZone(java.time.ZoneOffset.UTC).toLocalDate(),
-
java.time.Instant.ofEpochMilli(right.value).atZone(java.time.ZoneOffset.UTC).toLocalDate());
- int days = between.getDays();
- if (timeMilliseconds < 0 && days > 0) {
- // in the case of negative time value increases left operand days value
- between = java.time.Period.between(
- java.time.Instant.ofEpochMilli(left.value +
org.apache.drill.exec.vector.DateUtilities.daysToStandardMillis).atZone(java.time.ZoneOffset.UTC).toLocalDate(),
-
java.time.Instant.ofEpochMilli(right.value).atZone(java.time.ZoneOffset.UTC).toLocalDate());
- } else if (timeMilliseconds > 0 && days < 0) {
- // in the case of negative days value decreases it for the right
operand
- between = java.time.Period.between(
- java.time.Instant.ofEpochMilli(left.value -
org.apache.drill.exec.vector.DateUtilities.daysToStandardMillis).atZone(java.time.ZoneOffset.UTC).toLocalDate(),
-
java.time.Instant.ofEpochMilli(right.value).atZone(java.time.ZoneOffset.UTC).toLocalDate());
- }
- int months = between.getMonths() + between.getYears() *
org.apache.drill.exec.vector.DateUtilities.yearsToMonths;
+
+ java.time.LocalDateTime from =
java.time.Instant.ofEpochMilli(left.value).atZone(java.time.ZoneOffset.UTC).toLocalDateTime();
+ java.time.LocalDateTime to =
java.time.Instant.ofEpochMilli(right.value).atZone(java.time.ZoneOffset.UTC).toLocalDateTime();
+
+ int months = (int) from.until(to, java.time.temporal.ChronoUnit.MONTHS);
<#if unit == "Month">
out.value = months;
diff --git
a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/impl/DateTypeFunctions.java
b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/impl/DateTypeFunctions.java
index afd5f5d..523869a 100644
---
a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/impl/DateTypeFunctions.java
+++
b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/impl/DateTypeFunctions.java
@@ -42,560 +42,542 @@ import io.netty.buffer.DrillBuf;
public class DateTypeFunctions {
- /**
- * Function to check if a varchar value can be cast to a date.
- *
- * At the time of writing this function, several other databases were
checked
- * for behavior compatibility. There was not a consensus between oracle and
- * Sql server about the expected behavior of this function, and Postgres
- * lacks it completely.
- *
- * Sql Server appears to have both a DATEFORMAT and language locale setting
- * that can change the values accepted by this function. Oracle appears to
- * support several formats, some of which are not mentioned in the Sql
- * Server docs. With the lack of standardization, we decided to implement
- * this function so that it would only consider date strings that would be
- * accepted by the cast function as valid.
- */
- @SuppressWarnings("unused")
- @FunctionTemplate(name = "isdate", scope =
FunctionTemplate.FunctionScope.SIMPLE, nulls=NullHandling.INTERNAL,
- costCategory = FunctionTemplate.FunctionCostCategory.COMPLEX)
- public static class IsDate implements DrillSimpleFunc {
-
- @Param NullableVarCharHolder in;
- @Output BitHolder out;
-
- @Override
- public void setup() { }
-
- @Override
- public void eval() {
- // for a null input return false
- if (in.isSet == 0) {
- out.value = 0;
- } else {
- out.value =
org.apache.drill.exec.expr.fn.impl.StringFunctionHelpers.isReadableAsDate(in.buffer,
in.start, in.end) ? 1 : 0;
- }
+ /**
+ * Function to check if a varchar value can be cast to a date.
+ *
+ * At the time of writing this function, several other databases were checked
+ * for behavior compatibility. There was not a consensus between oracle and
Sql
+ * server about the expected behavior of this function, and Postgres lacks it
+ * completely.
+ *
+ * Sql Server appears to have both a DATEFORMAT and language locale setting
that
+ * can change the values accepted by this function. Oracle appears to support
+ * several formats, some of which are not mentioned in the Sql Server docs.
With
+ * the lack of standardization, we decided to implement this function so
that it
+ * would only consider date strings that would be accepted by the cast
function
+ * as valid.
+ */
+ @SuppressWarnings("unused")
+ @FunctionTemplate(name = "isdate", scope =
FunctionTemplate.FunctionScope.SIMPLE, nulls = NullHandling.INTERNAL,
costCategory = FunctionTemplate.FunctionCostCategory.COMPLEX)
+ public static class IsDate implements DrillSimpleFunc {
+
+ @Param
+ NullableVarCharHolder in;
+ @Output
+ BitHolder out;
+
+ @Override
+ public void setup() {
+ }
+
+ @Override
+ public void eval() {
+ // for a null input return false
+ if (in.isSet == 0) {
+ out.value = 0;
+ } else {
+ out.value =
org.apache.drill.exec.expr.fn.impl.StringFunctionHelpers.isReadableAsDate(in.buffer,
+ in.start, in.end) ? 1 : 0;
}
}
+ }
- // Same as above, just for required input
- @SuppressWarnings("unused")
- @FunctionTemplate(name = "isdate", scope =
FunctionTemplate.FunctionScope.SIMPLE, nulls=NullHandling.INTERNAL,
- costCategory = FunctionTemplate.FunctionCostCategory.COMPLEX)
- public static class IsDateRequiredInput implements DrillSimpleFunc {
+ // Same as above, just for required input
+ @SuppressWarnings("unused")
+ @FunctionTemplate(name = "isdate", scope =
FunctionTemplate.FunctionScope.SIMPLE, nulls = NullHandling.INTERNAL,
costCategory = FunctionTemplate.FunctionCostCategory.COMPLEX)
+ public static class IsDateRequiredInput implements DrillSimpleFunc {
- @Param VarCharHolder in;
- @Output BitHolder out;
+ @Param
+ VarCharHolder in;
+ @Output
+ BitHolder out;
- @Override
- public void setup() { }
+ @Override
+ public void setup() {
+ }
- @Override
- public void eval() {
- // for a null input return false
- out.value =
org.apache.drill.exec.expr.fn.impl.StringFunctionHelpers.isReadableAsDate(in.buffer,
in.start, in.end) ? 1 : 0;
- }
+ @Override
+ public void eval() {
+ // for a null input return false
+ out.value =
org.apache.drill.exec.expr.fn.impl.StringFunctionHelpers.isReadableAsDate(in.buffer,
in.start,
+ in.end) ? 1 : 0;
+ }
+ }
+
+ @FunctionTemplate(name = "intervaltype", scope =
FunctionTemplate.FunctionScope.SIMPLE, nulls = NullHandling.NULL_IF_NULL)
+ public static class IntervalType implements DrillSimpleFunc {
+
+ @Param
+ BigIntHolder inputYears;
+ @Param
+ BigIntHolder inputMonths;
+ @Param
+ BigIntHolder inputDays;
+ @Param
+ BigIntHolder inputHours;
+ @Param
+ BigIntHolder inputMinutes;
+ @Param
+ BigIntHolder inputSeconds;
+ @Param
+ BigIntHolder inputMilliSeconds;
+ @Output
+ IntervalHolder out;
+
+ @Override
+ public void setup() {
}
- @FunctionTemplate(name = "intervaltype", scope =
FunctionTemplate.FunctionScope.SIMPLE, nulls = NullHandling.NULL_IF_NULL)
- public static class IntervalType implements DrillSimpleFunc {
+ @Override
+ public void eval() {
- @Param BigIntHolder inputYears;
- @Param BigIntHolder inputMonths;
- @Param BigIntHolder inputDays;
- @Param BigIntHolder inputHours;
- @Param BigIntHolder inputMinutes;
- @Param BigIntHolder inputSeconds;
- @Param BigIntHolder inputMilliSeconds;
- @Output IntervalHolder out;
-
- @Override
- public void setup() {
- }
-
- @Override
- public void eval() {
-
- out.months = (int) ((inputYears.value *
org.apache.drill.exec.vector.DateUtilities.yearsToMonths) +
- (inputMonths.value));
- out.days = (int) inputDays.value;
- out.milliseconds = (int) ((inputHours.value *
org.apache.drill.exec.vector.DateUtilities.hoursToMillis) +
- (inputMinutes.value *
org.apache.drill.exec.vector.DateUtilities.minutesToMillis) +
- (inputSeconds.value *
org.apache.drill.exec.vector.DateUtilities.secondsToMillis) +
- (inputMilliSeconds.value));
- }
- }
-
- @FunctionTemplate(name = "interval_year", scope =
FunctionTemplate.FunctionScope.SIMPLE, nulls = NullHandling.NULL_IF_NULL)
- public static class IntervalYearType implements DrillSimpleFunc {
-
- @Param BigIntHolder inputYears;
- @Param BigIntHolder inputMonths;
- @Output IntervalYearHolder out;
-
- @Override
- public void setup() {
- }
-
- @Override
- public void eval() {
-
- out.value = (int) ((inputYears.value *
org.apache.drill.exec.vector.DateUtilities.yearsToMonths) +
- (inputMonths.value));
- }
- }
-
- @FunctionTemplate(name = "interval_day", scope =
FunctionTemplate.FunctionScope.SIMPLE, nulls = NullHandling.NULL_IF_NULL)
- public static class IntervalDayType implements DrillSimpleFunc {
-
- @Param BigIntHolder inputDays;
- @Param BigIntHolder inputHours;
- @Param BigIntHolder inputMinutes;
- @Param BigIntHolder inputSeconds;
- @Param BigIntHolder inputMillis;
- @Output IntervalDayHolder out;
-
- @Override
- public void setup() {
- }
-
- @Override
- public void eval() {
-
- out.days = (int) inputDays.value;
- out.milliseconds = (int) ((inputHours.value *
org.apache.drill.exec.vector.DateUtilities.hoursToMillis) +
- (inputMinutes.value *
org.apache.drill.exec.vector.DateUtilities.minutesToMillis) +
- (inputSeconds.value *
org.apache.drill.exec.vector.DateUtilities.secondsToMillis) +
- (inputMillis.value));
- }
- }
-
- @FunctionTemplate(name = "datetype", scope =
FunctionTemplate.FunctionScope.SIMPLE, nulls = NullHandling.NULL_IF_NULL)
- public static class DateType implements DrillSimpleFunc {
-
- @Param BigIntHolder inputYears;
- @Param BigIntHolder inputMonths;
- @Param BigIntHolder inputDays;
- @Output DateHolder out;
-
- @Override
- public void setup() {
- }
-
- @Override
- public void eval() {
- out.value = ((new org.joda.time.MutableDateTime((int)
inputYears.value,
- (int)
inputMonths.value,
-
(int)inputDays.value,
- 0,
- 0,
- 0,
- 0,
-
org.joda.time.DateTimeZone.UTC))).getMillis();
- }
- }
-
- @FunctionTemplate(name = "timestamptype", scope =
FunctionTemplate.FunctionScope.SIMPLE, nulls = NullHandling.NULL_IF_NULL)
- public static class TimeStampType implements DrillSimpleFunc {
-
- @Param BigIntHolder inputYears;
- @Param BigIntHolder inputMonths;
- @Param BigIntHolder inputDays;
- @Param BigIntHolder inputHours;
- @Param BigIntHolder inputMinutes;
- @Param BigIntHolder inputSeconds;
- @Param BigIntHolder inputMilliSeconds;
- @Output TimeStampHolder out;
-
- @Override
- public void setup() {
- }
-
- @Override
- public void eval() {
- out.value = ((new
org.joda.time.MutableDateTime((int)inputYears.value,
-
(int)inputMonths.value,
-
(int)inputDays.value,
-
(int)inputHours.value,
-
(int)inputMinutes.value,
-
(int)inputSeconds.value,
-
(int)inputMilliSeconds.value,
-
org.joda.time.DateTimeZone.UTC))).getMillis();
- }
- }
-
- @FunctionTemplate(name = "timetype", scope =
FunctionTemplate.FunctionScope.SIMPLE, nulls = NullHandling.NULL_IF_NULL)
- public static class TimeType implements DrillSimpleFunc {
-
- @Param BigIntHolder inputHours;
- @Param BigIntHolder inputMinutes;
- @Param BigIntHolder inputSeconds;
- @Param BigIntHolder inputMilliSeconds;
- @Output TimeHolder out;
-
- @Override
- public void setup() {
- }
-
- @Override
- public void eval() {
- out.value = (int) ((inputHours.value *
org.apache.drill.exec.vector.DateUtilities.hoursToMillis) +
- (inputMinutes.value *
org.apache.drill.exec.vector.DateUtilities.minutesToMillis) +
- (inputSeconds.value *
org.apache.drill.exec.vector.DateUtilities.secondsToMillis) +
- inputMilliSeconds.value);
- }
- }
-
- @FunctionTemplate(name = "current_date", scope =
FunctionTemplate.FunctionScope.SIMPLE, nulls = NullHandling.NULL_IF_NULL,
isNiladic = true)
- public static class CurrentDate implements DrillSimpleFunc {
- @Workspace long queryStartDate;
- @Output DateHolder out;
- @Inject ContextInformation contextInfo;
-
- @Override
- public void setup() {
-
- int timeZoneIndex = contextInfo.getRootFragmentTimeZone();
- org.joda.time.DateTimeZone timeZone =
org.joda.time.DateTimeZone.forID(org.apache.drill.exec.expr.fn.impl.DateUtility.getTimeZone(timeZoneIndex));
- org.joda.time.DateTime now = new
org.joda.time.DateTime(contextInfo.getQueryStartTime(), timeZone);
- queryStartDate = (new org.joda.time.DateMidnight(now.getYear(),
now.getMonthOfYear(), now.getDayOfMonth(), timeZone)).
-
withZoneRetainFields(org.joda.time.DateTimeZone.UTC).getMillis();
- }
-
- @Override
- public void eval() {
- out.value = queryStartDate;
- }
-
- }
-
- @FunctionTemplate(name = "timeofday", scope =
FunctionTemplate.FunctionScope.SIMPLE, nulls = NullHandling.NULL_IF_NULL,
isRandom = true,
- outputSizeEstimate =
OutputSizeEstimateConstants.DATE_TIME_LENGTH)
- public static class TimeOfDay implements DrillSimpleFunc {
- @Inject DrillBuf buffer;
- @Output VarCharHolder out;
-
- @Override
- public void setup() {
- }
-
- @Override
- public void eval() {
- java.time.ZonedDateTime temp = java.time.ZonedDateTime.now();
- String str =
org.apache.drill.exec.expr.fn.impl.DateUtility.formatTimeStampTZ.format(temp);
- out.buffer = buffer;
- out.start = 0;
- out.end = Math.min(100, str.length()); // truncate if target type
has length smaller than that of input's string
- out.buffer.setBytes(0, str.substring(0,out.end).getBytes());
- }
- }
-
- /*
- * Return query start time in milliseconds
- */
- public static long getQueryStartDate(ContextInformation contextInfo) {
- org.joda.time.DateTime now = (new
org.joda.time.DateTime(contextInfo.getQueryStartTime())).withZoneRetainFields(org.joda.time.DateTimeZone.UTC);
- return now.getMillis();
- }
-
- /*
- * Niladic version of LocalTimeStamp
- */
- @FunctionTemplate(names = {"localtimestamp", "current_timestamp"}, scope =
FunctionTemplate.FunctionScope.SIMPLE, nulls = NullHandling.NULL_IF_NULL,
isNiladic = true)
- public static class LocalTimeStampNiladic implements DrillSimpleFunc {
- @Workspace long queryStartDate;
- @Output TimeStampHolder out;
- @Inject ContextInformation contextInfo;
-
- @Override
- public void setup() {
- queryStartDate =
org.apache.drill.exec.expr.fn.impl.DateTypeFunctions.getQueryStartDate(contextInfo);
- }
-
- @Override
- public void eval() {
- out.value = queryStartDate;
- }
- }
-
- /*
- * Non-Niladic version of LocalTimeStamp
- */
- @FunctionTemplate(names = {"now", "statement_timestamp",
"transaction_timestamp"}, scope = FunctionTemplate.FunctionScope.SIMPLE, nulls
= NullHandling.NULL_IF_NULL)
- public static class LocalTimeStampNonNiladic implements DrillSimpleFunc {
- @Workspace long queryStartDate;
- @Output TimeStampHolder out;
- @Inject ContextInformation contextInfo;
-
- @Override
- public void setup() {
- queryStartDate =
org.apache.drill.exec.expr.fn.impl.DateTypeFunctions.getQueryStartDate(contextInfo);
- }
-
- @Override
- public void eval() {
- out.value = queryStartDate;
- }
- }
-
- @FunctionTemplate(names = {"current_time", "localtime"}, scope =
FunctionTemplate.FunctionScope.SIMPLE, nulls = NullHandling.NULL_IF_NULL,
isNiladic = true)
- public static class CurrentTime implements DrillSimpleFunc {
- @Workspace int queryStartTime;
- @Output TimeHolder out;
- @Inject ContextInformation contextInfo;
-
- @Override
- public void setup() {
-
- int timeZoneIndex = contextInfo.getRootFragmentTimeZone();
- org.joda.time.DateTimeZone timeZone =
org.joda.time.DateTimeZone.forID(org.apache.drill.exec.expr.fn.impl.DateUtility.getTimeZone(timeZoneIndex));
- org.joda.time.DateTime now = new
org.joda.time.DateTime(contextInfo.getQueryStartTime(), timeZone);
- queryStartTime= (now.getHourOfDay() *
org.apache.drill.exec.vector.DateUtilities.hoursToMillis) +
- (now.getMinuteOfHour() *
org.apache.drill.exec.vector.DateUtilities.minutesToMillis) +
- (now.getSecondOfMinute() *
org.apache.drill.exec.vector.DateUtilities.secondsToMillis) +
- (now.getMillisOfSecond());
- }
-
- @Override
- public void eval() {
- out.value = queryStartTime;
- }
- }
-
- @SuppressWarnings("unused")
- @FunctionTemplate(names = {"date_add", "add"}, scope =
FunctionTemplate.FunctionScope.SIMPLE, nulls=NullHandling.NULL_IF_NULL)
- public static class DateTimeAddFunction implements DrillSimpleFunc {
- @Param DateHolder left;
- @Param TimeHolder right;
- @Output TimeStampHolder out;
-
- @Override
- public void setup() {
- }
-
- @Override
- public void eval() {
- out.value = left.value + right.value;
- }
- }
-
- @SuppressWarnings("unused")
- @FunctionTemplate(names = {"date_add", "add"}, scope =
FunctionTemplate.FunctionScope.SIMPLE, nulls=NullHandling.NULL_IF_NULL)
- public static class TimeDateAddFunction implements DrillSimpleFunc {
- @Param TimeHolder right;
- @Param DateHolder left;
- @Output TimeStampHolder out;
-
- @Override
- public void setup() {
- }
-
- @Override
- public void eval() {
- out.value = left.value + right.value;
- }
- }
-
- /* Dummy function template to allow Optiq to validate this function call.
- * At DrillOptiq time we rewrite all date_part() functions to extract
functions,
- * since they are essentially the same
- */
- @SuppressWarnings("unused")
- @FunctionTemplate(names = "date_part", scope =
FunctionTemplate.FunctionScope.SIMPLE, nulls=NullHandling.NULL_IF_NULL)
- public static class DatePartFunction implements DrillSimpleFunc {
- @Param VarCharHolder left;
- @Param DateHolder right;
- @Output BigIntHolder out;
-
- @Override
- public void setup() {
- }
-
- @Override
- public void eval() {
- if (1 == 1) {
- throw new UnsupportedOperationException("date_part function
should be rewritten as extract() functions");
- }
- }
- }
-
- @FunctionTemplate(name = "age", scope =
FunctionTemplate.FunctionScope.SIMPLE, nulls = NullHandling.NULL_IF_NULL)
- public static class AgeTimeStampFunction implements DrillSimpleFunc {
- @Param TimeStampHolder left;
- @Param TimeStampHolder right;
- @Output IntervalHolder out;
-
- @Override
- public void setup() {
- }
-
- @Override
- public void eval() {
- long diff = left.value - right.value;
- long days = diff /
org.apache.drill.exec.vector.DateUtilities.daysToStandardMillis;
- out.months = (int) (days /
org.apache.drill.exec.vector.DateUtilities.monthToStandardDays);
- out.days = (int) (days %
org.apache.drill.exec.vector.DateUtilities.monthToStandardDays);
- out.milliseconds = (int) (diff %
org.apache.drill.exec.vector.DateUtilities.daysToStandardMillis);
- }
- }
-
- @FunctionTemplate(name = "age", scope =
FunctionTemplate.FunctionScope.SIMPLE, nulls = NullHandling.NULL_IF_NULL)
- public static class AgeTimeStamp2Function implements DrillSimpleFunc {
- @Param TimeStampHolder right;
- @Workspace long queryStartDate;
- @Output IntervalHolder out;
- @Inject ContextInformation contextInfo;
-
- @Override
- public void setup() {
- int timeZoneIndex = contextInfo.getRootFragmentTimeZone();
- org.joda.time.DateTimeZone timeZone =
org.joda.time.DateTimeZone.forID(org.apache.drill.exec.expr.fn.impl.DateUtility.getTimeZone(timeZoneIndex));
- org.joda.time.DateTime now = new
org.joda.time.DateTime(contextInfo.getQueryStartTime(), timeZone);
- queryStartDate = (new org.joda.time.DateMidnight(now.getYear(),
now.getMonthOfYear(), now.getDayOfMonth(), timeZone)).getMillis();
- }
-
- @Override
- public void eval() {
- long diff = queryStartDate - right.value;
- long days = diff /
org.apache.drill.exec.vector.DateUtilities.daysToStandardMillis;
- out.months = (int) (days /
org.apache.drill.exec.vector.DateUtilities.monthToStandardDays);
- out.days = (int) (days %
org.apache.drill.exec.vector.DateUtilities.monthToStandardDays);
- out.milliseconds = (int) (diff %
org.apache.drill.exec.vector.DateUtilities.daysToStandardMillis);
- }
- }
-
- @FunctionTemplate(name = "age", scope =
FunctionTemplate.FunctionScope.SIMPLE, nulls = NullHandling.NULL_IF_NULL)
- public static class AgeDateFunction implements DrillSimpleFunc {
- @Param DateHolder left;
- @Param DateHolder right;
- @Output IntervalHolder out;
-
- @Override
- public void setup() {
- }
-
- @Override
- public void eval() {
- long diff = left.value - right.value;
- long days = diff /
org.apache.drill.exec.vector.DateUtilities.daysToStandardMillis;
- out.months = (int) (days /
org.apache.drill.exec.vector.DateUtilities.monthToStandardDays);
- out.days = (int) (days %
org.apache.drill.exec.vector.DateUtilities.monthToStandardDays);
- out.milliseconds = (int) (diff %
org.apache.drill.exec.vector.DateUtilities.daysToStandardMillis);
- }
- }
-
- @FunctionTemplate(name = "age", scope =
FunctionTemplate.FunctionScope.SIMPLE, nulls = NullHandling.NULL_IF_NULL)
- public static class AgeDate2Function implements DrillSimpleFunc {
- @Param DateHolder right;
- @Workspace long queryStartDate;
- @Output IntervalHolder out;
- @Inject ContextInformation contextInfo;
-
- @Override
- public void setup() {
- int timeZoneIndex = contextInfo.getRootFragmentTimeZone();
- org.joda.time.DateTimeZone timeZone =
org.joda.time.DateTimeZone.forID(org.apache.drill.exec.expr.fn.impl.DateUtility.getTimeZone(timeZoneIndex));
- org.joda.time.DateTime now = new
org.joda.time.DateTime(contextInfo.getQueryStartTime(), timeZone);
- queryStartDate = (new org.joda.time.DateMidnight(now.getYear(),
now.getMonthOfYear(), now.getDayOfMonth(), timeZone)).getMillis();
- }
-
- @Override
- public void eval() {
- long diff = queryStartDate - right.value;
- long days = diff /
org.apache.drill.exec.vector.DateUtilities.daysToStandardMillis;
- out.months = (int) (days /
org.apache.drill.exec.vector.DateUtilities.monthToStandardDays);
- out.days = (int) (days %
org.apache.drill.exec.vector.DateUtilities.monthToStandardDays);
- out.milliseconds = (int) (diff %
org.apache.drill.exec.vector.DateUtilities.daysToStandardMillis);
- }
- }
-
- @FunctionTemplate(name = "castTIME", scope =
FunctionTemplate.FunctionScope.SIMPLE, nulls = NullHandling.NULL_IF_NULL)
- public static class CastTimeStampToTime implements DrillSimpleFunc {
- @Param TimeStampHolder in;
- @Output TimeHolder out;
-
- @Override
- public void setup() {
- }
-
- @Override
- public void eval() {
- out.value = (int) (in.value %
org.apache.drill.exec.vector.DateUtilities.daysToStandardMillis);
- }
- }
-
- @FunctionTemplate(name = "castTIME", scope =
FunctionTemplate.FunctionScope.SIMPLE, nulls = NullHandling.NULL_IF_NULL)
- public static class CastDateToTime implements DrillSimpleFunc {
- @Param DateHolder in;
- @Output TimeHolder out;
-
- @Override
- public void setup() {
- }
+ out.months = (int) ((inputYears.value *
org.apache.drill.exec.vector.DateUtilities.yearsToMonths)
+ + (inputMonths.value));
+ out.days = (int) inputDays.value;
+ out.milliseconds = (int) ((inputHours.value *
org.apache.drill.exec.vector.DateUtilities.hoursToMillis)
+ + (inputMinutes.value *
org.apache.drill.exec.vector.DateUtilities.minutesToMillis)
+ + (inputSeconds.value *
org.apache.drill.exec.vector.DateUtilities.secondsToMillis)
+ + (inputMilliSeconds.value));
+ }
+ }
- @Override
- public void eval() {
- out.value = 0;
- }
+ @FunctionTemplate(name = "interval_year", scope =
FunctionTemplate.FunctionScope.SIMPLE, nulls = NullHandling.NULL_IF_NULL)
+ public static class IntervalYearType implements DrillSimpleFunc {
+
+ @Param
+ BigIntHolder inputYears;
+ @Param
+ BigIntHolder inputMonths;
+ @Output
+ IntervalYearHolder out;
+
+ @Override
+ public void setup() {
}
- @FunctionTemplate(name = "unix_timestamp", scope =
FunctionTemplate.FunctionScope.SIMPLE, nulls = NullHandling.NULL_IF_NULL)
- public static class UnixTimeStamp implements DrillSimpleFunc {
- @Output BigIntHolder out;
- @Workspace long queryStartDate;
- @Inject ContextInformation contextInfo;
+ @Override
+ public void eval() {
- @Override
- public void setup() {
- queryStartDate = contextInfo.getQueryStartTime();
- }
+ out.value = (int) ((inputYears.value *
org.apache.drill.exec.vector.DateUtilities.yearsToMonths)
+ + (inputMonths.value));
+ }
+ }
+
+ @FunctionTemplate(name = "interval_day", scope =
FunctionTemplate.FunctionScope.SIMPLE, nulls = NullHandling.NULL_IF_NULL)
+ public static class IntervalDayType implements DrillSimpleFunc {
+
+ @Param
+ BigIntHolder inputDays;
+ @Param
+ BigIntHolder inputHours;
+ @Param
+ BigIntHolder inputMinutes;
+ @Param
+ BigIntHolder inputSeconds;
+ @Param
+ BigIntHolder inputMillis;
+ @Output
+ IntervalDayHolder out;
+
+ @Override
+ public void setup() {
+ }
- @Override
- public void eval() {
- out.value = queryStartDate / 1000;
- }
+ @Override
+ public void eval() {
+
+ out.days = (int) inputDays.value;
+ out.milliseconds = (int) ((inputHours.value *
org.apache.drill.exec.vector.DateUtilities.hoursToMillis)
+ + (inputMinutes.value *
org.apache.drill.exec.vector.DateUtilities.minutesToMillis)
+ + (inputSeconds.value *
org.apache.drill.exec.vector.DateUtilities.secondsToMillis)
+ + (inputMillis.value));
+ }
+ }
+
+ @FunctionTemplate(name = "datetype", scope =
FunctionTemplate.FunctionScope.SIMPLE, nulls = NullHandling.NULL_IF_NULL)
+ public static class DateType implements DrillSimpleFunc {
+
+ @Param
+ BigIntHolder inputYears;
+ @Param
+ BigIntHolder inputMonths;
+ @Param
+ BigIntHolder inputDays;
+ @Output
+ DateHolder out;
+
+ @Override
+ public void setup() {
}
- @FunctionTemplate(name = "unix_timestamp", scope =
FunctionTemplate.FunctionScope.SIMPLE, nulls = NullHandling.NULL_IF_NULL)
- public static class UnixTimeStampForDate implements DrillSimpleFunc {
- @Param VarCharHolder inputDateValue;
- @Output BigIntHolder out;
- @Workspace org.joda.time.DateTime date;
- @Workspace org.joda.time.format.DateTimeFormatter formatter;
+ @Override
+ public void eval() {
+ out.value = ((new org.joda.time.MutableDateTime((int) inputYears.value,
(int) inputMonths.value,
+ (int) inputDays.value, 0, 0, 0, 0,
org.joda.time.DateTimeZone.UTC))).getMillis();
+ }
+ }
+
+ @FunctionTemplate(name = "timestamptype", scope =
FunctionTemplate.FunctionScope.SIMPLE, nulls = NullHandling.NULL_IF_NULL)
+ public static class TimeStampType implements DrillSimpleFunc {
+
+ @Param
+ BigIntHolder inputYears;
+ @Param
+ BigIntHolder inputMonths;
+ @Param
+ BigIntHolder inputDays;
+ @Param
+ BigIntHolder inputHours;
+ @Param
+ BigIntHolder inputMinutes;
+ @Param
+ BigIntHolder inputSeconds;
+ @Param
+ BigIntHolder inputMilliSeconds;
+ @Output
+ TimeStampHolder out;
+
+ @Override
+ public void setup() {
+ }
- @Override
- public void setup() {
- formatter =
org.joda.time.format.DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");
- }
+ @Override
+ public void eval() {
+ out.value = ((new org.joda.time.MutableDateTime((int) inputYears.value,
(int) inputMonths.value,
+ (int) inputDays.value, (int) inputHours.value, (int)
inputMinutes.value, (int) inputSeconds.value,
+ (int) inputMilliSeconds.value,
org.joda.time.DateTimeZone.UTC))).getMillis();
+ }
+ }
+
+ @FunctionTemplate(name = "timetype", scope =
FunctionTemplate.FunctionScope.SIMPLE, nulls = NullHandling.NULL_IF_NULL)
+ public static class TimeType implements DrillSimpleFunc {
+
+ @Param
+ BigIntHolder inputHours;
+ @Param
+ BigIntHolder inputMinutes;
+ @Param
+ BigIntHolder inputSeconds;
+ @Param
+ BigIntHolder inputMilliSeconds;
+ @Output
+ TimeHolder out;
+
+ @Override
+ public void setup() {
+ }
- @Override
- public void eval() {
- String inputDate =
org.apache.drill.exec.expr.fn.impl.StringFunctionHelpers.toStringFromUTF8(inputDateValue.start,
inputDateValue.end, inputDateValue.buffer);
- date = formatter.parseDateTime(inputDate);
- out.value = date.getMillis() / 1000;
- }
+ @Override
+ public void eval() {
+ out.value = (int) ((inputHours.value *
org.apache.drill.exec.vector.DateUtilities.hoursToMillis)
+ + (inputMinutes.value *
org.apache.drill.exec.vector.DateUtilities.minutesToMillis)
+ + (inputSeconds.value *
org.apache.drill.exec.vector.DateUtilities.secondsToMillis)
+ + inputMilliSeconds.value);
+ }
+ }
+
+ @FunctionTemplate(name = "current_date", scope =
FunctionTemplate.FunctionScope.SIMPLE, nulls = NullHandling.NULL_IF_NULL,
isNiladic = true)
+ public static class CurrentDate implements DrillSimpleFunc {
+ @Workspace
+ long queryStartDate;
+ @Output
+ DateHolder out;
+ @Inject
+ ContextInformation contextInfo;
+
+ @Override
+ public void setup() {
+ java.time.Instant queryStart = contextInfo.getQueryStartInstant();
+ java.time.ZonedDateTime lzdt =
queryStart.atZone(contextInfo.getRootFragmentTimeZone());
+ java.time.LocalDate ld =
lzdt.truncatedTo(java.time.temporal.ChronoUnit.DAYS).toLocalDate();
+ queryStartDate =
org.apache.drill.exec.vector.DateUtilities.toDrillDate(ld);
}
- @FunctionTemplate(name = "unix_timestamp", scope =
FunctionTemplate.FunctionScope.SIMPLE, nulls = NullHandling.NULL_IF_NULL)
- public static class UnixTimeStampForDateWithPattern implements
DrillSimpleFunc {
- @Param VarCharHolder inputDateValue;
- @Param VarCharHolder inputPattern;
- @Output BigIntHolder out;
- @Workspace org.joda.time.DateTime date;
- @Workspace org.joda.time.format.DateTimeFormatter formatter;
+ @Override
+ public void eval() {
+ out.value = queryStartDate;
+ }
- @Override
- public void setup() {
- String pattern =
org.apache.drill.exec.expr.fn.impl.StringFunctionHelpers.toStringFromUTF8(inputPattern.start,
inputPattern.end, inputPattern.buffer);
- formatter = org.joda.time.format.DateTimeFormat.forPattern(pattern);
- }
+ }
+
+ @FunctionTemplate(name = "timeofday", scope =
FunctionTemplate.FunctionScope.SIMPLE, nulls = NullHandling.NULL_IF_NULL,
isRandom = true, outputSizeEstimate =
OutputSizeEstimateConstants.DATE_TIME_LENGTH)
+ public static class TimeOfDay implements DrillSimpleFunc {
+ @Inject
+ DrillBuf buffer;
+ @Output
+ VarCharHolder out;
+
+ @Override
+ public void setup() {
+ }
- @Override
- public void eval() {
- String inputDate =
org.apache.drill.exec.expr.fn.impl.StringFunctionHelpers.toStringFromUTF8(inputDateValue.start,
inputDateValue.end, inputDateValue.buffer);
- date = formatter.parseDateTime(inputDate);
- out.value = date.getMillis() / 1000;
+ @Override
+ public void eval() {
+ java.time.ZonedDateTime temp = java.time.ZonedDateTime.now();
+ String str =
org.apache.drill.exec.expr.fn.impl.DateUtility.formatTimeStampTZ.format(temp);
+ out.buffer = buffer;
+ out.start = 0;
+ out.end = Math.min(100, str.length()); // truncate if target type has
length smaller than that of input's
+ // string
+ out.buffer.setBytes(0, str.substring(0, out.end).getBytes());
+ }
+ }
+
+ /*
+ * Return query start time in milliseconds
+ */
+ public static long getQueryStartDate(ContextInformation contextInfo) {
+ org.joda.time.DateTime now = (new
org.joda.time.DateTime(contextInfo.getQueryStartTime()))
+ .withZoneRetainFields(org.joda.time.DateTimeZone.UTC);
+ return now.getMillis();
+ }
+
+ /*
+ * Niladic version of LocalTimeStamp
+ */
+ @FunctionTemplate(names = { "localtimestamp",
+ "current_timestamp" }, scope = FunctionTemplate.FunctionScope.SIMPLE,
nulls = NullHandling.NULL_IF_NULL, isNiladic = true)
+ public static class LocalTimeStampNiladic implements DrillSimpleFunc {
+ @Workspace
+ long queryStartDate;
+ @Output
+ TimeStampHolder out;
+ @Inject
+ ContextInformation contextInfo;
+
+ @Override
+ public void setup() {
+ queryStartDate =
org.apache.drill.exec.expr.fn.impl.DateTypeFunctions.getQueryStartDate(contextInfo);
+ }
+
+ @Override
+ public void eval() {
+ out.value = queryStartDate;
+ }
+ }
+
+ /*
+ * Non-Niladic version of LocalTimeStamp
+ */
+ @FunctionTemplate(names = { "now", "statement_timestamp",
+ "transaction_timestamp" }, scope =
FunctionTemplate.FunctionScope.SIMPLE, nulls = NullHandling.NULL_IF_NULL)
+ public static class LocalTimeStampNonNiladic implements DrillSimpleFunc {
+ @Workspace
+ long queryStartDate;
+ @Output
+ TimeStampHolder out;
+ @Inject
+ ContextInformation contextInfo;
+
+ @Override
+ public void setup() {
+ queryStartDate =
org.apache.drill.exec.expr.fn.impl.DateTypeFunctions.getQueryStartDate(contextInfo);
+ }
+
+ @Override
+ public void eval() {
+ out.value = queryStartDate;
+ }
+ }
+
+ @FunctionTemplate(names = { "current_time",
+ "localtime" }, scope = FunctionTemplate.FunctionScope.SIMPLE, nulls =
NullHandling.NULL_IF_NULL, isNiladic = true)
+ public static class CurrentTime implements DrillSimpleFunc {
+ @Workspace
+ int queryStartTime;
+ @Output
+ TimeHolder out;
+ @Inject
+ ContextInformation contextInfo;
+
+ @Override
+ public void setup() {
+ java.time.Instant queryStart = contextInfo.getQueryStartInstant();
+ java.time.ZonedDateTime lzdt =
queryStart.atZone(contextInfo.getRootFragmentTimeZone());
+ queryStartTime =
org.apache.drill.exec.vector.DateUtilities.toDrillTime(lzdt.toLocalTime());
+ }
+
+ @Override
+ public void eval() {
+ out.value = queryStartTime;
+ }
+ }
+
+ @SuppressWarnings("unused")
+ @FunctionTemplate(names = { "date_add",
+ "add" }, scope = FunctionTemplate.FunctionScope.SIMPLE, nulls =
NullHandling.NULL_IF_NULL)
+ public static class DateTimeAddFunction implements DrillSimpleFunc {
+ @Param
+ DateHolder left;
+ @Param
+ TimeHolder right;
+ @Output
+ TimeStampHolder out;
+
+ @Override
+ public void setup() {
+ }
+
+ @Override
+ public void eval() {
+ out.value = left.value + right.value;
+ }
+ }
+
+ @SuppressWarnings("unused")
+ @FunctionTemplate(names = { "date_add",
+ "add" }, scope = FunctionTemplate.FunctionScope.SIMPLE, nulls =
NullHandling.NULL_IF_NULL)
+ public static class TimeDateAddFunction implements DrillSimpleFunc {
+ @Param
+ TimeHolder right;
+ @Param
+ DateHolder left;
+ @Output
+ TimeStampHolder out;
+
+ @Override
+ public void setup() {
+ }
+
+ @Override
+ public void eval() {
+ out.value = left.value + right.value;
+ }
+ }
+
+ /*
+ * Dummy function template to allow Optiq to validate this function call. At
+ * DrillOptiq time we rewrite all date_part() functions to extract functions,
+ * since they are essentially the same
+ */
+ @SuppressWarnings("unused")
+ @FunctionTemplate(names = "date_part", scope =
FunctionTemplate.FunctionScope.SIMPLE, nulls = NullHandling.NULL_IF_NULL)
+ public static class DatePartFunction implements DrillSimpleFunc {
+ @Param
+ VarCharHolder left;
+ @Param
+ DateHolder right;
+ @Output
+ BigIntHolder out;
+
+ @Override
+ public void setup() {
+ }
+
+ @Override
+ public void eval() {
+ if (1 == 1) {
+ throw new UnsupportedOperationException(
+ "date_part function should be rewritten as extract() functions");
}
}
+ }
+
+ @FunctionTemplate(name = "castTIME", scope =
FunctionTemplate.FunctionScope.SIMPLE, nulls = NullHandling.NULL_IF_NULL)
+ public static class CastTimeStampToTime implements DrillSimpleFunc {
+ @Param
+ TimeStampHolder in;
+ @Output
+ TimeHolder out;
+
+ @Override
+ public void setup() {
+ }
+
+ @Override
+ public void eval() {
+ out.value = (int) (in.value %
org.apache.drill.exec.vector.DateUtilities.daysToStandardMillis);
+ }
+ }
+
+ @FunctionTemplate(name = "castTIME", scope =
FunctionTemplate.FunctionScope.SIMPLE, nulls = NullHandling.NULL_IF_NULL)
+ public static class CastDateToTime implements DrillSimpleFunc {
+ @Param
+ DateHolder in;
+ @Output
+ TimeHolder out;
+
+ @Override
+ public void setup() {
+ }
+
+ @Override
+ public void eval() {
+ out.value = 0;
+ }
+ }
+
+ @FunctionTemplate(name = "unix_timestamp", scope =
FunctionTemplate.FunctionScope.SIMPLE, nulls = NullHandling.NULL_IF_NULL)
+ public static class UnixTimeStamp implements DrillSimpleFunc {
+ @Output
+ BigIntHolder out;
+ @Workspace
+ long queryStartDate;
+ @Inject
+ ContextInformation contextInfo;
+
+ @Override
+ public void setup() {
+ queryStartDate = contextInfo.getQueryStartTime();
+ }
+
+ @Override
+ public void eval() {
+ out.value = queryStartDate / 1000;
+ }
+ }
+
+ @FunctionTemplate(name = "unix_timestamp", scope =
FunctionTemplate.FunctionScope.SIMPLE, nulls = NullHandling.NULL_IF_NULL)
+ public static class UnixTimeStampForDate implements DrillSimpleFunc {
+ @Param
+ VarCharHolder inputDateValue;
+ @Output
+ BigIntHolder out;
+ @Workspace
+ org.joda.time.DateTime date;
+ @Workspace
+ org.joda.time.format.DateTimeFormatter formatter;
+
+ @Override
+ public void setup() {
+ formatter = org.joda.time.format.DateTimeFormat.forPattern("yyyy-MM-dd
HH:mm:ss");
+ }
+
+ @Override
+ public void eval() {
+ String inputDate =
org.apache.drill.exec.expr.fn.impl.StringFunctionHelpers
+ .toStringFromUTF8(inputDateValue.start, inputDateValue.end,
inputDateValue.buffer);
+ date = formatter.parseDateTime(inputDate);
+ out.value = date.getMillis() / 1000;
+ }
+ }
+
+ @FunctionTemplate(name = "unix_timestamp", scope =
FunctionTemplate.FunctionScope.SIMPLE, nulls = NullHandling.NULL_IF_NULL)
+ public static class UnixTimeStampForDateWithPattern implements
DrillSimpleFunc {
+ @Param
+ VarCharHolder inputDateValue;
+ @Param
+ VarCharHolder inputPattern;
+ @Output
+ BigIntHolder out;
+ @Workspace
+ org.joda.time.DateTime date;
+ @Workspace
+ org.joda.time.format.DateTimeFormatter formatter;
+
+ @Override
+ public void setup() {
+ String pattern = org.apache.drill.exec.expr.fn.impl.StringFunctionHelpers
+ .toStringFromUTF8(inputPattern.start, inputPattern.end,
inputPattern.buffer);
+ formatter = org.joda.time.format.DateTimeFormat.forPattern(pattern);
+ }
+
+ @Override
+ public void eval() {
+ String inputDate =
org.apache.drill.exec.expr.fn.impl.StringFunctionHelpers
+ .toStringFromUTF8(inputDateValue.start, inputDateValue.end,
inputDateValue.buffer);
+ date = formatter.parseDateTime(inputDate);
+ out.value = date.getMillis() / 1000;
+ }
+ }
}
diff --git
a/exec/java-exec/src/main/java/org/apache/drill/exec/ops/ContextInformation.java
b/exec/java-exec/src/main/java/org/apache/drill/exec/ops/ContextInformation.java
index 1972cb7..24fcd10 100644
---
a/exec/java-exec/src/main/java/org/apache/drill/exec/ops/ContextInformation.java
+++
b/exec/java-exec/src/main/java/org/apache/drill/exec/ops/ContextInformation.java
@@ -19,6 +19,9 @@ package org.apache.drill.exec.ops;
import org.apache.drill.exec.proto.BitControl.QueryContextInformation;
import org.apache.drill.exec.proto.UserBitShared.UserCredentials;
+import java.time.Instant;
+import java.time.ZoneId;
+import org.apache.drill.exec.expr.fn.impl.DateUtility;
/**
* Provides query context information (such as query start time, query user,
default schema etc.) for UDFs.
@@ -53,17 +56,25 @@ public class ContextInformation {
}
/**
- * @return Query start time in milliseconds
+ * @return Query start time in Unix time (ms)
*/
public long getQueryStartTime() {
return queryStartTime;
}
/**
- * @return Time zone.
+ * @return Query start time as an Instant
*/
- public int getRootFragmentTimeZone() {
- return rootFragmentTimeZone;
+ public Instant getQueryStartInstant() {
+ return Instant.ofEpochMilli(queryStartTime);
+ }
+
+ /**
+ * @return Query time zone as a ZoneId
+ */
+ public ZoneId getRootFragmentTimeZone() {
+ String zoneId = DateUtility.getTimeZone(rootFragmentTimeZone);
+ return ZoneId.of(zoneId);
}
/**
diff --git
a/exec/java-exec/src/test/java/org/apache/drill/exec/fn/impl/TestDateFunctions.java
b/exec/java-exec/src/test/java/org/apache/drill/exec/fn/impl/TestDateFunctions.java
index 8c4bf8e..1c8b079 100644
---
a/exec/java-exec/src/test/java/org/apache/drill/exec/fn/impl/TestDateFunctions.java
+++
b/exec/java-exec/src/test/java/org/apache/drill/exec/fn/impl/TestDateFunctions.java
@@ -104,10 +104,19 @@ public class TestDateFunctions extends PopUnitTestBase {
@Test
public void testAge() throws Exception {
- String[] expectedResults = {"P109M16DT82800S",
- "P172M27D",
- "P-172M-27D",
- "P-39M-18DT-63573S"};
+ String[] expectedResults = {
+ "P107M30DT82800S",
+ "P108MT3600S",
+ "P170M12D",
+ "P-170M-12D",
+ "P-39M-2DT-63573S",
+ "P-39M-3DT-22827S",
+ "PT3540S",
+ "PT0S",
+ "PT0S",
+ "P-3D",
+ "P2DT84600S"
+ };
testCommon(expectedResults, "/functions/date/age.json",
"/test_simple_date.json");
}
diff --git a/exec/java-exec/src/test/resources/functions/date/age.json
b/exec/java-exec/src/test/resources/functions/date/age.json
index 23ebf38..b455cad 100644
--- a/exec/java-exec/src/test/resources/functions/date/age.json
+++ b/exec/java-exec/src/test/resources/functions/date/age.json
@@ -28,18 +28,39 @@
"ref" : "TS1",
"expr" : "age(cast('2010-01-01 10:10:10' as timestamp), cast('2001-01-01
11:10:10' as timestamp))"
}, {
+ "ref" : "TS2",
+ "expr" : "age(cast('2010-01-01 11:10:10' as timestamp), cast('2001-01-01
10:10:10' as timestamp))"
+ }, {
"ref" : "D1",
"expr" : "age(cast('2005-07-11' as date), cast('1991-04-29' as date))"
}, {
"ref" : "D2",
"expr" : "age(cast('1991-04-29' as date), cast('2005-07-11' as date))"
}, {
- "ref" : "TS2",
+ "ref" : "TS3",
"expr" : "age(cast('1997-12-17 23:37:54' as timestamp), cast('2001-03-20
17:17:27' as timestamp))"
+ }, {
+ "ref" : "TS4",
+ "expr" : "age(cast('1997-12-17 17:17:27' as timestamp), cast('2001-03-20
23:37:54' as timestamp))"
+ }, {
+ "ref" : "TS5",
+ "expr" : "age(cast('2021-02-01 00:29:00' as timestamp), cast('2021-01-31
23:30:00' as timestamp))"
+ }, {
+ "ref" : "UD1",
+ "expr" : "age(current_date())"
+ }, {
+ "ref" : "UTS1",
+ "expr" : "age(cast(current_date() as timestamp))"
+ }, {
+ "ref" : "UD2",
+ "expr" : "age(add(current_date(), 3))"
+ }, {
+ "ref" : "UTS2",
+ "expr" : "age(subtract(add(subtract(current_date() , cast('P3D' as
INTERVALDAY)) , cast('PT3600S' as INTERVALDAY)) , cast('PT1800S' as
INTERVALDAY)))"
} ]
}, {
"@id" : 3,
"child" : 2,
"pop" : "screen"
} ]
-}
\ No newline at end of file
+}