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 <x...@selectdb.com> --- 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: commits-unsubscr...@doris.apache.org For additional commands, e-mail: commits-h...@doris.apache.org