[NO ISSUE][FUN] Add quarter_of_year() function
- user model changes: no
- storage format changes: no
- interface changes: no
Details:
- Add quarter_of_year() function that returns
a quarter of the year for datetime and date values
- Add tests and update documentation
Change-Id: I6905b2ec8dbd28556454e37053c0e276730941c7
Reviewed-on: https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/13285
Integration-Tests: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Tested-by: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Reviewed-by: Dmitry Lychagin <dmitry.lychagin@couchbase.com>
Reviewed-by: Ian Maxon <imaxon@uci.edu>
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/temporal/TemporalQueries.xml b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/temporal/TemporalQueries.xml
index 8fb387e..8b48ca6 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/temporal/TemporalQueries.xml
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/temporal/TemporalQueries.xml
@@ -83,6 +83,11 @@
</compilation-unit>
</test-case>
<test-case FilePath="temporal">
+ <compilation-unit name="quarter_of_year_01">
+ <output-dir compare="Text">quarter_of_year_01</output-dir>
+ </compilation-unit>
+ </test-case>
+ <test-case FilePath="temporal">
<compilation-unit name="interval_bin">
<output-dir compare="Text">interval_bin</output-dir>
</compilation-unit>
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/temporal/quarter_of_year_01/quarter_of_year_01.1.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/temporal/quarter_of_year_01/quarter_of_year_01.1.query.sqlpp
new file mode 100644
index 0000000..a11b3c1
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/temporal/quarter_of_year_01/quarter_of_year_01.1.query.sqlpp
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+/*
+ * Quarter of year
+ */
+
+select month, qoy1, qoy2, count(*) cnt
+from range(0, 365) r
+let
+ s = unix_time_from_date_in_days(date("2020-01-01")),
+ d = date_from_unix_time_in_days(s + r),
+ dt = datetime_from_date_time(d, time("01:01:01")),
+ month = get_month(d),
+ qoy1 = quarter_of_year(d),
+ qoy2 = quarter_of_year(dt)
+group by qoy1, qoy2, month
+order by qoy1, qoy2, month;
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/temporal/quarter_of_year_01/quarter_of_year_01.1.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/temporal/quarter_of_year_01/quarter_of_year_01.1.adm
new file mode 100644
index 0000000..9537fbe
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/temporal/quarter_of_year_01/quarter_of_year_01.1.adm
@@ -0,0 +1,12 @@
+{ "month": 1, "qoy1": 1, "qoy2": 1, "cnt": 31 }
+{ "month": 2, "qoy1": 1, "qoy2": 1, "cnt": 29 }
+{ "month": 3, "qoy1": 1, "qoy2": 1, "cnt": 31 }
+{ "month": 4, "qoy1": 2, "qoy2": 2, "cnt": 30 }
+{ "month": 5, "qoy1": 2, "qoy2": 2, "cnt": 31 }
+{ "month": 6, "qoy1": 2, "qoy2": 2, "cnt": 30 }
+{ "month": 7, "qoy1": 3, "qoy2": 3, "cnt": 31 }
+{ "month": 8, "qoy1": 3, "qoy2": 3, "cnt": 31 }
+{ "month": 9, "qoy1": 3, "qoy2": 3, "cnt": 30 }
+{ "month": 10, "qoy1": 4, "qoy2": 4, "cnt": 31 }
+{ "month": 11, "qoy1": 4, "qoy2": 4, "cnt": 30 }
+{ "month": 12, "qoy1": 4, "qoy2": 4, "cnt": 31 }
\ No newline at end of file
diff --git a/asterixdb/asterix-doc/src/main/markdown/builtins/7_temporal.md b/asterixdb/asterix-doc/src/main/markdown/builtins/7_temporal.md
index 2e08b77..dcb252b 100644
--- a/asterixdb/asterix-doc/src/main/markdown/builtins/7_temporal.md
+++ b/asterixdb/asterix-doc/src/main/markdown/builtins/7_temporal.md
@@ -394,6 +394,28 @@
{ "week_1": 48, "week_2": 49, "week_3": 49, "week_4": 49 }
+### quarter_of_year ###
+* Syntax:
+
+ quarter_of_year(date)
+
+* Finds the quarter of the year for a given date
+* Arguments:
+ * `date`: a `date` or a `datetime` value
+* Return Value:
+ * an `bigint` representing the quarter of the year (1_4),
+ * `missing` if the argument is a `missing` value,
+ * `null` if the argument is a `null` value,
+ * any other non-date input value will cause a type error.
+
+* Example:
+
+ quarter_of_year(date("2011-12-31"));
+
+* The expected result is:
+
+ 4
+
### datetime_from_date_time ###
* Syntax:
diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/base/temporal/GregorianCalendarSystem.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/base/temporal/GregorianCalendarSystem.java
index c8d171f..2f838be 100644
--- a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/base/temporal/GregorianCalendarSystem.java
+++ b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/base/temporal/GregorianCalendarSystem.java
@@ -654,6 +654,14 @@
}
/**
+ * Get the quarter of the year for the given chronon time and the year.
+ */
+ public int getQuarterOfYear(long millis, int year) {
+ int month = getMonthOfYear(millis, year);
+ return (month - 1) / 3 + 1;
+ }
+
+ /**
* Get the hour of the day for the given chronon time.
*
* @param millis
diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/functions/BuiltinFunctions.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/functions/BuiltinFunctions.java
index 14b4bab..f9f61fe 100644
--- a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/functions/BuiltinFunctions.java
+++ b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/functions/BuiltinFunctions.java
@@ -1471,6 +1471,8 @@
new FunctionIdentifier(FunctionConstants.ASTERIX_NS, "day-of-week", 2);
public static final FunctionIdentifier DAY_OF_YEAR =
new FunctionIdentifier(FunctionConstants.ASTERIX_NS, "day-of-year", 1);
+ public static final FunctionIdentifier QUARTER_OF_YEAR =
+ new FunctionIdentifier(FunctionConstants.ASTERIX_NS, "quarter-of-year", 1);
public static final FunctionIdentifier WEEK_OF_YEAR =
new FunctionIdentifier(FunctionConstants.ASTERIX_NS, "week-of-year", 1);
public static final FunctionIdentifier WEEK_OF_YEAR2 =
@@ -2383,6 +2385,7 @@
addFunction(DAY_OF_WEEK, AInt64TypeComputer.INSTANCE, true);
addFunction(DAY_OF_WEEK2, AInt64TypeComputer.INSTANCE_NULLABLE, true);
addFunction(DAY_OF_YEAR, AInt64TypeComputer.INSTANCE, true);
+ addFunction(QUARTER_OF_YEAR, AInt64TypeComputer.INSTANCE, true);
addFunction(WEEK_OF_YEAR, AInt64TypeComputer.INSTANCE, true);
addFunction(WEEK_OF_YEAR2, AInt64TypeComputer.INSTANCE_NULLABLE, true);
addFunction(PARSE_DATE, ADateTypeComputer.INSTANCE, true);
diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/temporal/QuarterOfYearDescriptor.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/temporal/QuarterOfYearDescriptor.java
new file mode 100644
index 0000000..bd54db0
--- /dev/null
+++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/temporal/QuarterOfYearDescriptor.java
@@ -0,0 +1,143 @@
+/*
+ * 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.asterix.runtime.evaluators.functions.temporal;
+
+import java.io.DataOutput;
+import java.io.IOException;
+
+import org.apache.asterix.common.annotations.MissingNullInOutFunction;
+import org.apache.asterix.dataflow.data.nontagged.serde.ADurationSerializerDeserializer;
+import org.apache.asterix.dataflow.data.nontagged.serde.AInt32SerializerDeserializer;
+import org.apache.asterix.dataflow.data.nontagged.serde.AInt64SerializerDeserializer;
+import org.apache.asterix.dataflow.data.nontagged.serde.AYearMonthDurationSerializerDeserializer;
+import org.apache.asterix.formats.nontagged.SerializerDeserializerProvider;
+import org.apache.asterix.om.base.AInt64;
+import org.apache.asterix.om.base.AMutableInt64;
+import org.apache.asterix.om.base.temporal.GregorianCalendarSystem;
+import org.apache.asterix.om.functions.BuiltinFunctions;
+import org.apache.asterix.om.functions.IFunctionDescriptorFactory;
+import org.apache.asterix.om.types.ATypeTag;
+import org.apache.asterix.om.types.BuiltinType;
+import org.apache.asterix.runtime.evaluators.base.AbstractScalarFunctionDynamicDescriptor;
+import org.apache.asterix.runtime.evaluators.functions.PointableHelper;
+import org.apache.asterix.runtime.exceptions.TypeMismatchException;
+import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
+import org.apache.hyracks.algebricks.runtime.base.IEvaluatorContext;
+import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluator;
+import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluatorFactory;
+import org.apache.hyracks.api.dataflow.value.ISerializerDeserializer;
+import org.apache.hyracks.api.exceptions.HyracksDataException;
+import org.apache.hyracks.data.std.api.IPointable;
+import org.apache.hyracks.data.std.primitive.VoidPointable;
+import org.apache.hyracks.data.std.util.ArrayBackedValueStorage;
+import org.apache.hyracks.dataflow.common.data.accessors.IFrameTupleReference;
+
+@MissingNullInOutFunction
+public class QuarterOfYearDescriptor extends AbstractScalarFunctionDynamicDescriptor {
+ private static final long serialVersionUID = 1L;
+ private static final FunctionIdentifier FID = BuiltinFunctions.QUARTER_OF_YEAR;
+ public static final IFunctionDescriptorFactory FACTORY = QuarterOfYearDescriptor::new;
+
+ @Override
+ public IScalarEvaluatorFactory createEvaluatorFactory(final IScalarEvaluatorFactory[] args) {
+ return new IScalarEvaluatorFactory() {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public IScalarEvaluator createScalarEvaluator(IEvaluatorContext ctx) throws HyracksDataException {
+ return new IScalarEvaluator() {
+ private final ArrayBackedValueStorage resultStorage = new ArrayBackedValueStorage();
+ private final DataOutput out = resultStorage.getDataOutput();
+ private final IPointable argPtr = new VoidPointable();
+ private final IScalarEvaluator eval = args[0].createScalarEvaluator(ctx);
+
+ private final GregorianCalendarSystem calSystem = GregorianCalendarSystem.getInstance();
+
+ // for output: type integer
+ @SuppressWarnings("unchecked")
+ private final ISerializerDeserializer<AInt64> intSerde =
+ SerializerDeserializerProvider.INSTANCE.getSerializerDeserializer(BuiltinType.AINT64);
+ private final AMutableInt64 aMutableInt64 = new AMutableInt64(0);
+
+ @Override
+ public void evaluate(IFrameTupleReference tuple, IPointable result) throws HyracksDataException {
+ eval.evaluate(tuple, argPtr);
+
+ if (PointableHelper.checkAndSetMissingOrNull(result, argPtr)) {
+ return;
+ }
+
+ byte[] bytes = argPtr.getByteArray();
+ int startOffset = argPtr.getStartOffset();
+
+ resultStorage.reset();
+ try {
+ if (bytes[startOffset] == ATypeTag.SERIALIZED_DURATION_TYPE_TAG) {
+ int durationMonth = calSystem.getDurationMonth(
+ ADurationSerializerDeserializer.getYearMonth(bytes, startOffset + 1));
+ int durationQuarter = durationMonth / 3;
+ aMutableInt64.setValue(durationQuarter);
+ intSerde.serialize(aMutableInt64, out);
+ result.set(resultStorage);
+ return;
+ }
+ if (bytes[startOffset] == ATypeTag.SERIALIZED_YEAR_MONTH_DURATION_TYPE_TAG) {
+ int durationMonth = calSystem.getDurationMonth(
+ AYearMonthDurationSerializerDeserializer.getYearMonth(bytes, startOffset + 1));
+ int durationQuarter = durationMonth / 3;
+ aMutableInt64.setValue(durationQuarter);
+ intSerde.serialize(aMutableInt64, out);
+ result.set(resultStorage);
+ return;
+ }
+
+ long chrononTimeInMs;
+ if (bytes[startOffset] == ATypeTag.SERIALIZED_DATE_TYPE_TAG) {
+ chrononTimeInMs = AInt32SerializerDeserializer.getInt(bytes, startOffset + 1)
+ * GregorianCalendarSystem.CHRONON_OF_DAY;
+ } else if (bytes[startOffset] == ATypeTag.SERIALIZED_DATETIME_TYPE_TAG) {
+ chrononTimeInMs = AInt64SerializerDeserializer.getLong(bytes, startOffset + 1);
+ } else {
+ throw new TypeMismatchException(sourceLoc, getIdentifier(), 0, bytes[startOffset],
+ ATypeTag.SERIALIZED_DURATION_TYPE_TAG,
+ ATypeTag.SERIALIZED_YEAR_MONTH_DURATION_TYPE_TAG,
+ ATypeTag.SERIALIZED_DATE_TYPE_TAG, ATypeTag.SERIALIZED_DATETIME_TYPE_TAG);
+ }
+
+ int year = calSystem.getYear(chrononTimeInMs);
+ int quarter = calSystem.getQuarterOfYear(chrononTimeInMs, year);
+
+ aMutableInt64.setValue(quarter);
+ intSerde.serialize(aMutableInt64, out);
+ } catch (IOException e) {
+ throw HyracksDataException.create(e);
+ }
+ result.set(resultStorage);
+ }
+ };
+ }
+ };
+ }
+
+ @Override
+ public FunctionIdentifier getIdentifier() {
+ return FID;
+ }
+}
diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/functions/FunctionCollection.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/functions/FunctionCollection.java
index 3677bc8..cc9cca9 100644
--- a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/functions/FunctionCollection.java
+++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/functions/FunctionCollection.java
@@ -566,6 +566,7 @@
import org.apache.asterix.runtime.evaluators.functions.temporal.PrintDateDescriptor;
import org.apache.asterix.runtime.evaluators.functions.temporal.PrintDateTimeDescriptor;
import org.apache.asterix.runtime.evaluators.functions.temporal.PrintTimeDescriptor;
+import org.apache.asterix.runtime.evaluators.functions.temporal.QuarterOfYearDescriptor;
import org.apache.asterix.runtime.evaluators.functions.temporal.TimeFromDatetimeDescriptor;
import org.apache.asterix.runtime.evaluators.functions.temporal.TimeFromUnixTimeInMsDescriptor;
import org.apache.asterix.runtime.evaluators.functions.temporal.UnixTimeFromDateInDaysDescriptor;
@@ -1188,6 +1189,7 @@
fc.add(DayOfWeekDescriptor.FACTORY);
fc.add(DayOfWeek2Descriptor.FACTORY);
fc.add(DayOfYearDescriptor.FACTORY);
+ fc.add(QuarterOfYearDescriptor.FACTORY);
fc.add(WeekOfYearDescriptor.FACTORY);
fc.add(WeekOfYear2Descriptor.FACTORY);
fc.add(ParseDateDescriptor.FACTORY);