This is an automated email from the ASF dual-hosted git repository.
dataroaring pushed a commit to branch branch-3.0
in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/branch-3.0 by this push:
new 11ce43f1faa branch-3.0: [Feature](function) support year of week
#48870 (#49011)
11ce43f1faa is described below
commit 11ce43f1faa029ea323028cdd6d7cfff16ef0c68
Author: github-actions[bot]
<41898282+github-actions[bot]@users.noreply.github.com>
AuthorDate: Sun Mar 30 10:52:12 2025 +0800
branch-3.0: [Feature](function) support year of week #48870 (#49011)
Cherry-picked from #48870
Co-authored-by: Pxl <[email protected]>
---
be/src/vec/functions/date_time_transforms.h | 17 ++++-
be/src/vec/functions/to_time_function.cpp | 10 +--
be/src/vec/runtime/vdatetime_value.cpp | 26 +++++++
be/src/vec/runtime/vdatetime_value.h | 1 +
be/test/vec/function/function_time_test.cpp | 12 +++
.../doris/catalog/BuiltinScalarFunctions.java | 2 +
.../doris/nereids/stats/ExpressionEstimation.java | 16 ++++
.../expressions/functions/scalar/YearOfWeek.java | 84 +++++++++++++++++++++
.../expressions/visitor/ScalarFunctionVisitor.java | 5 ++
.../datetime_functions/test_date_function.out | Bin 10292 -> 10699 bytes
.../datetime_functions/test_date_function.groovy | 24 ++++++
11 files changed, 186 insertions(+), 11 deletions(-)
diff --git a/be/src/vec/functions/date_time_transforms.h
b/be/src/vec/functions/date_time_transforms.h
index 33accd9f706..f20e2255e26 100644
--- a/be/src/vec/functions/date_time_transforms.h
+++ b/be/src/vec/functions/date_time_transforms.h
@@ -58,6 +58,7 @@ namespace doris::vectorized {
#define TO_TIME_FUNCTION(CLASS, UNIT) TIME_FUNCTION_IMPL(CLASS, UNIT, UNIT())
TO_TIME_FUNCTION(ToYearImpl, year);
+TO_TIME_FUNCTION(ToYearOfWeekImpl, year_of_week);
TO_TIME_FUNCTION(ToQuarterImpl, quarter);
TO_TIME_FUNCTION(ToMonthImpl, month);
TO_TIME_FUNCTION(ToDayImpl, day);
@@ -395,8 +396,8 @@ struct Transformer {
}
};
-template <typename FromType, typename ToType>
-struct Transformer<FromType, ToType, ToYearImpl<FromType>> {
+template <typename FromType, typename ToType, template <typename> typename
Impl>
+struct TransformerYear {
static void vector(const PaddedPODArray<FromType>& vec_from,
PaddedPODArray<ToType>& vec_to,
NullMap& null_map) {
size_t size = vec_from.size();
@@ -408,7 +409,7 @@ struct Transformer<FromType, ToType, ToYearImpl<FromType>> {
auto* __restrict null_map_ptr = null_map.data();
for (size_t i = 0; i < size; ++i) {
- to_ptr[i] = ToYearImpl<FromType>::execute(from_ptr[i]);
+ to_ptr[i] = Impl<FromType>::execute(from_ptr[i]);
}
for (size_t i = 0; i < size; ++i) {
@@ -424,11 +425,19 @@ struct Transformer<FromType, ToType,
ToYearImpl<FromType>> {
auto* __restrict from_ptr = vec_from.data();
for (size_t i = 0; i < size; ++i) {
- to_ptr[i] = ToYearImpl<FromType>::execute(from_ptr[i]);
+ to_ptr[i] = Impl<FromType>::execute(from_ptr[i]);
}
}
};
+template <typename FromType, typename ToType>
+struct Transformer<FromType, ToType, ToYearImpl<FromType>>
+ : public TransformerYear<FromType, ToType, ToYearImpl> {};
+
+template <typename FromType, typename ToType>
+struct Transformer<FromType, ToType, ToYearOfWeekImpl<FromType>>
+ : public TransformerYear<FromType, ToType, ToYearOfWeekImpl> {};
+
template <typename FromType, typename ToType, typename Transform>
struct DateTimeTransformImpl {
static Status execute(Block& block, const ColumnNumbers& arguments, size_t
result,
diff --git a/be/src/vec/functions/to_time_function.cpp
b/be/src/vec/functions/to_time_function.cpp
index 126296fc40a..f160ad531a3 100644
--- a/be/src/vec/functions/to_time_function.cpp
+++ b/be/src/vec/functions/to_time_function.cpp
@@ -16,15 +16,8 @@
// specific language governing permissions and limitations
// under the License.
-#include <algorithm>
-#include <boost/iterator/iterator_facade.hpp>
-#include <memory>
-#include <utility>
-
#include "vec/core/types.h"
-#include "vec/data_types/data_type.h"
#include "vec/data_types/data_type_date_time.h"
-#include "vec/data_types/data_type_nullable.h"
#include "vec/data_types/data_type_number.h"
#include "vec/data_types/data_type_time_v2.h"
#include "vec/functions/date_time_transforms.h"
@@ -35,6 +28,8 @@ namespace doris::vectorized {
using FunctionYear = FunctionDateOrDateTimeToSomething<DataTypeInt16,
ToYearImpl<Int64>>;
using FunctionYearV2 = FunctionDateOrDateTimeToSomething<DataTypeInt16,
ToYearImpl<UInt32>>;
+using FunctionYearOfWeek =
+ FunctionDateOrDateTimeToSomething<DataTypeInt16,
ToYearOfWeekImpl<UInt32>>;
using FunctionQuarter = FunctionDateOrDateTimeToSomething<DataTypeInt8,
ToQuarterImpl<Int64>>;
using FunctionQuarterV2 = FunctionDateOrDateTimeToSomething<DataTypeInt8,
ToQuarterImpl<UInt32>>;
using FunctionMonth = FunctionDateOrDateTimeToSomething<DataTypeInt8,
ToMonthImpl<Int64>>;
@@ -102,6 +97,7 @@ void
register_function_to_time_function(SimpleFunctionFactory& factory) {
factory.register_function<FunctionWeekV2>();
factory.register_function<FunctionMonthV2>();
factory.register_function<FunctionYearV2>();
+ factory.register_function<FunctionYearOfWeek>();
factory.register_function<FunctionQuarterV2>();
factory.register_function<FunctionToDaysV2>();
factory.register_function<FunctionToDateV2>();
diff --git a/be/src/vec/runtime/vdatetime_value.cpp
b/be/src/vec/runtime/vdatetime_value.cpp
index 877573bcccb..4f889ce7f1f 100644
--- a/be/src/vec/runtime/vdatetime_value.cpp
+++ b/be/src/vec/runtime/vdatetime_value.cpp
@@ -3812,6 +3812,32 @@ bool DateV2Value<T>::from_date_int64(int64_t value) {
}
}
+// An ISO week-numbering year (also called ISO year informally) has 52 or 53
full weeks. That is 364 or 371 days instead of the usual 365 or 366 days. These
53-week years occur on all years that have Thursday as 1 January and on leap
years that start on Wednesday. The extra week is sometimes referred to as a
leap week, although ISO 8601 does not use this term.
https://en.wikipedia.org/wiki/ISO_week_date
+template <typename T>
+uint16_t DateV2Value<T>::year_of_week() const {
+ constexpr uint8_t THURSDAY = 3;
+
+ if (date_v2_value_.month_ == 1) {
+ constexpr uint8_t MAX_DISTANCE_WITH_THURSDAY = 6 - THURSDAY;
+ if (date_v2_value_.day_ <= MAX_DISTANCE_WITH_THURSDAY) {
+ auto weekday = calc_weekday(daynr(), false);
+ // if the current day is after Thursday and Thursday is in the
previous year, return the previous year
+ return date_v2_value_.year_ -
+ (weekday > THURSDAY && weekday - THURSDAY >
date_v2_value_.day_ - 1);
+ }
+ } else if (date_v2_value_.month_ == 12) {
+ constexpr uint8_t MAX_DISTANCE_WITH_THURSDAY = THURSDAY - 0;
+ if (S_DAYS_IN_MONTH[12] - date_v2_value_.day_ <=
MAX_DISTANCE_WITH_THURSDAY) {
+ auto weekday = calc_weekday(daynr(), false);
+ // if the current day is before Thursday and Thursday is in the
next year, return the next year
+ return date_v2_value_.year_ +
+ (weekday < THURSDAY &&
+ (THURSDAY - weekday) > S_DAYS_IN_MONTH[12] -
date_v2_value_.day_);
+ }
+ }
+ return date_v2_value_.year_;
+}
+
template <typename T>
uint8_t DateV2Value<T>::calc_week(const uint32_t& day_nr, const uint16_t& year,
const uint8_t& month, const uint8_t& day,
uint8_t mode,
diff --git a/be/src/vec/runtime/vdatetime_value.h
b/be/src/vec/runtime/vdatetime_value.h
index ebda0e60ec1..0c991c14e4a 100644
--- a/be/src/vec/runtime/vdatetime_value.h
+++ b/be/src/vec/runtime/vdatetime_value.h
@@ -937,6 +937,7 @@ public:
}
uint16_t year() const { return date_v2_value_.year_; }
+ uint16_t year_of_week() const;
uint8_t month() const { return date_v2_value_.month_; }
int quarter() const { return (date_v2_value_.month_ - 1) / 3 + 1; }
int week() const { return week(mysql_week_mode(0)); } //00-53
diff --git a/be/test/vec/function/function_time_test.cpp
b/be/test/vec/function/function_time_test.cpp
index a4299de3557..17f487287ec 100644
--- a/be/test/vec/function/function_time_test.cpp
+++ b/be/test/vec/function/function_time_test.cpp
@@ -1773,4 +1773,16 @@ TEST(VTimestampFunctionsTest, seconds_sub_v2_test) {
}
}
+TEST(VTimestampFunctionsTest, year_of_week_test) {
+ std::string func_name = "year_of_week";
+ {
+ InputTypeSet input_types = {TypeIndex::DateV2};
+ DataSet data_set = {{{std::string("2005-01-01")}, int16_t(2004)},
+ {{std::string("2008-12-30")}, int16_t(2009)},
+ {{std::string("12008-12-30")}, Null()},
+ {{Null()}, Null()}};
+ static_cast<void>(check_function<DataTypeInt16, true>(func_name,
input_types, data_set));
+ }
+}
+
} // namespace doris::vectorized
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/catalog/BuiltinScalarFunctions.java
b/fe/fe-core/src/main/java/org/apache/doris/catalog/BuiltinScalarFunctions.java
index 08cb73d910f..3d9e12398f2 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/catalog/BuiltinScalarFunctions.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/catalog/BuiltinScalarFunctions.java
@@ -466,6 +466,7 @@ import
org.apache.doris.nereids.trees.expressions.functions.scalar.XxHash64;
import org.apache.doris.nereids.trees.expressions.functions.scalar.Year;
import org.apache.doris.nereids.trees.expressions.functions.scalar.YearCeil;
import org.apache.doris.nereids.trees.expressions.functions.scalar.YearFloor;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.YearOfWeek;
import org.apache.doris.nereids.trees.expressions.functions.scalar.YearWeek;
import org.apache.doris.nereids.trees.expressions.functions.scalar.YearsAdd;
import org.apache.doris.nereids.trees.expressions.functions.scalar.YearsDiff;
@@ -950,6 +951,7 @@ public class BuiltinScalarFunctions implements
FunctionHelper {
scalar(Year.class, "year"),
scalar(YearCeil.class, "year_ceil"),
scalar(YearFloor.class, "year_floor"),
+ scalar(YearOfWeek.class, "year_of_week", "yow"),
scalar(YearWeek.class, "yearweek"),
scalar(YearsAdd.class, "years_add"),
scalar(YearsDiff.class, "years_diff"),
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/stats/ExpressionEstimation.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/stats/ExpressionEstimation.java
index 2307a6dfba3..0bf027a9e9d 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/stats/ExpressionEstimation.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/stats/ExpressionEstimation.java
@@ -86,6 +86,7 @@ import
org.apache.doris.nereids.trees.expressions.functions.scalar.ToDays;
import org.apache.doris.nereids.trees.expressions.functions.scalar.WeekOfYear;
import org.apache.doris.nereids.trees.expressions.functions.scalar.WeeksDiff;
import org.apache.doris.nereids.trees.expressions.functions.scalar.Year;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.YearOfWeek;
import org.apache.doris.nereids.trees.expressions.functions.scalar.YearsAdd;
import org.apache.doris.nereids.trees.expressions.functions.scalar.YearsDiff;
import org.apache.doris.nereids.trees.expressions.functions.scalar.YearsSub;
@@ -402,6 +403,21 @@ public class ExpressionEstimation extends
ExpressionVisitor<ColumnStatistic, Sta
.setMaxValue(maxYear).setMinExpr(null).build();
}
+ @Override
+ public ColumnStatistic visitYearOfWeek(YearOfWeek yearOfWeek, Statistics
context) {
+ ColumnStatistic childStat = yearOfWeek.child().accept(this, context);
+ double rowCount = context.getRowCount();
+ long minYear = 1970;
+ long maxYear = 2038;
+ return new ColumnStatisticBuilder()
+ .setNdv(maxYear - minYear + 1)
+ .setAvgSizeByte(4)
+ .setNumNulls(childStat.numNulls)
+ .setDataSize(4 * rowCount)
+ .setMinValue(minYear)
+ .setMaxValue(maxYear).setMinExpr(null).build();
+ }
+
@Override
public ColumnStatistic visitWeekOfYear(WeekOfYear weekOfYear, Statistics
context) {
ColumnStatistic childStat = weekOfYear.child().accept(this, context);
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/YearOfWeek.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/YearOfWeek.java
new file mode 100644
index 00000000000..ff89d93227d
--- /dev/null
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/YearOfWeek.java
@@ -0,0 +1,84 @@
+// 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.doris.nereids.trees.expressions.functions.scalar;
+
+import org.apache.doris.catalog.FunctionSignature;
+import org.apache.doris.nereids.trees.expressions.Expression;
+import
org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSignature;
+import org.apache.doris.nereids.trees.expressions.functions.Monotonic;
+import
org.apache.doris.nereids.trees.expressions.functions.PropagateNullableOnDateLikeV2Args;
+import org.apache.doris.nereids.trees.expressions.shape.UnaryExpression;
+import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
+import org.apache.doris.nereids.types.DateV2Type;
+import org.apache.doris.nereids.types.SmallIntType;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+
+import java.util.List;
+
+/**
+ * ScalarFunction 'year_of_week'. This class is generated by GenerateFunction.
+ */
+public class YearOfWeek extends ScalarFunction
+ implements UnaryExpression, ExplicitlyCastableSignature,
PropagateNullableOnDateLikeV2Args, Monotonic {
+
+ private static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
+
FunctionSignature.ret(SmallIntType.INSTANCE).args(DateV2Type.INSTANCE));
+
+ /**
+ * constructor with 1 argument.
+ */
+ public YearOfWeek(Expression arg) {
+ super("year_of_week", arg);
+ }
+
+ /**
+ * withChildren.
+ */
+ @Override
+ public YearOfWeek withChildren(List<Expression> children) {
+ Preconditions.checkArgument(children.size() == 1);
+ return new YearOfWeek(children.get(0));
+ }
+
+ @Override
+ public List<FunctionSignature> getSignatures() {
+ return SIGNATURES;
+ }
+
+ @Override
+ public <R, C> R accept(ExpressionVisitor<R, C> visitor, C context) {
+ return visitor.visitYearOfWeek(this, context);
+ }
+
+ @Override
+ public boolean isPositive() {
+ return true;
+ }
+
+ @Override
+ public int getMonotonicFunctionChildIndex() {
+ return 0;
+ }
+
+ @Override
+ public Expression withConstantArgs(Expression literal) {
+ return new YearOfWeek(literal);
+ }
+}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ScalarFunctionVisitor.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ScalarFunctionVisitor.java
index 3d960ecbd89..75c4a166919 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ScalarFunctionVisitor.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ScalarFunctionVisitor.java
@@ -463,6 +463,7 @@ import
org.apache.doris.nereids.trees.expressions.functions.scalar.XxHash64;
import org.apache.doris.nereids.trees.expressions.functions.scalar.Year;
import org.apache.doris.nereids.trees.expressions.functions.scalar.YearCeil;
import org.apache.doris.nereids.trees.expressions.functions.scalar.YearFloor;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.YearOfWeek;
import org.apache.doris.nereids.trees.expressions.functions.scalar.YearWeek;
import org.apache.doris.nereids.trees.expressions.functions.scalar.YearsAdd;
import org.apache.doris.nereids.trees.expressions.functions.scalar.YearsDiff;
@@ -2204,6 +2205,10 @@ public interface ScalarFunctionVisitor<R, C> {
return visitScalarFunction(year, context);
}
+ default R visitYearOfWeek(YearOfWeek yearOfWeek, C context) {
+ return visitScalarFunction(yearOfWeek, context);
+ }
+
default R visitYearCeil(YearCeil yearCeil, C context) {
return visitScalarFunction(yearCeil, context);
}
diff --git
a/regression-test/data/query_p0/sql_functions/datetime_functions/test_date_function.out
b/regression-test/data/query_p0/sql_functions/datetime_functions/test_date_function.out
index 3f6f59b899c..6ea735d5471 100644
Binary files
a/regression-test/data/query_p0/sql_functions/datetime_functions/test_date_function.out
and
b/regression-test/data/query_p0/sql_functions/datetime_functions/test_date_function.out
differ
diff --git
a/regression-test/suites/query_p0/sql_functions/datetime_functions/test_date_function.groovy
b/regression-test/suites/query_p0/sql_functions/datetime_functions/test_date_function.groovy
index 8bd43dae685..db891c0f015 100644
---
a/regression-test/suites/query_p0/sql_functions/datetime_functions/test_date_function.groovy
+++
b/regression-test/suites/query_p0/sql_functions/datetime_functions/test_date_function.groovy
@@ -475,6 +475,30 @@ suite("test_date_function") {
qt_sql """ select year('2050-01-01') """
qt_sql """ select test_datetime, year(test_datetime) from ${tableName}
order by test_datetime """
+ // YEAROFWEEK
+ qt_sql """ select year_of_week('1987-01-01') """
+ qt_sql """ select year_of_week('2050-01-01') """
+ qt_sql """ select test_datetime, year_of_week(test_datetime) from
${tableName} order by test_datetime """
+
+ qt_sql """ select yow('1987-01-01') """
+
+ qt_sql "select year_of_week('2005-01-01')" // 2004-W53-6
+ qt_sql "select year_of_week('2005-01-02')" // 2004-W53-7
+ qt_sql "select year_of_week('2005-12-31')" // 2005-W52-6
+ qt_sql "select year_of_week('2007-01-01')" // 2007-W01-1
+ qt_sql "select year_of_week('2007-12-30')" // 2007-W52-7
+ qt_sql "select year_of_week('2007-12-31')" // 2008-W01-1
+ qt_sql "select year_of_week('2008-01-01')" // 2008-W01-2
+ qt_sql "select year_of_week('2008-12-28')" // 2008-W52-7
+ qt_sql "select year_of_week('2008-12-29')" // 2009-W01-1
+ qt_sql "select year_of_week('2008-12-30')" // 2009-W01-2
+ qt_sql "select year_of_week('2008-12-31')" // 2009-W01-3
+ qt_sql "select year_of_week('2009-01-01')" // 2009-W01-4
+ qt_sql "select year_of_week('2009-12-31')" // 2009-W53-4
+ qt_sql "select year_of_week('2010-01-01')" // 2009-W53-5
+ qt_sql "select year_of_week('2010-01-02')" // 2009-W53-6
+ qt_sql "select year_of_week('2010-01-03')" // 2009-W53-7
+
// YEARWEEK
qt_sql """ select yearweek('2021-1-1') """
qt_sql """ select yearweek('2020-7-1') """
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]