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

Reply via email to