This is an automated email from the ASF dual-hosted git repository.
zclll pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/master by this push:
new 42aeb9be714 (enhanced) completed the function : century from duckdb
(#57893)
42aeb9be714 is described below
commit 42aeb9be7140f87fe6b5492cb3b23bda4b258a7a
Author: robll-v1 <[email protected]>
AuthorDate: Wed Nov 26 10:21:01 2025 +0800
(enhanced) completed the function : century from duckdb (#57893)
mysql> CREATE TABLE IF NOT EXISTS test_century_function (
-> id int,
-> test_date date NULL,
-> test_datetime datetime NULL,
-> test_datetimev2 datetimev2(3) NULL,
-> test_date_str varchar(20) NULL
-> ) ENGINE=OLAP
-> DUPLICATE KEY(id)
-> COMMENT "OLAP"
-> DISTRIBUTED BY HASH(id) BUCKETS 1
-> PROPERTIES (
-> "replication_allocation" = "tag.location.default: 1",
-> "in_memory" = "false",
-> "storage_format" = "V2"
-> );
Query OK, 0 rows affected (0.03 sec)
mysql> INSERT INTO test_century_function VALUES
-> (1, '1989-03-21', '1989-03-21 10:30:45', '1989-03-21 10:30:45.123',
'1989-03-21'),
-> (2, '2000-01-01', '2000-01-01 00:00:00', '2000-01-01 00:00:00.000',
'2000-01-01'),
-> (3, '2001-01-01', '2001-01-01 12:30:45', '2001-01-01 12:30:45.456',
'2001-01-01'),
-> (4, '2015-07-14', '2015-07-14 15:45:30', '2015-07-14 15:45:30.789',
'2015-07-14'),
-> (5, '1900-12-31', '1900-12-31 23:59:59', '1900-12-31 23:59:59.999',
'1900-12-31'),
-> (6, '1901-01-01', '1901-01-01 00:00:00', '1901-01-01 00:00:00.000',
'1901-01-01'),
-> (7, '1999-12-31', '1999-12-31 23:59:59', '1999-12-31 23:59:59.999',
'1999-12-31'),
-> (8, '2001-01-01', '2001-01-01 00:00:00', '2001-01-01 00:00:00.000',
'2001-01-01'),
-> (9, '0001-01-01', '0001-01-01 00:00:00', '0001-01-01 00:00:00.000',
'0001-01-01'),
-> (10, '0100-12-31', '0100-12-31 23:59:59', '0100-12-31 23:59:59.999',
'0100-12-31'),
-> (11, '0101-01-01', '0101-01-01 00:00:00', '0101-01-01 00:00:00.000',
'0101-01-01'),
-> (12, '9999-12-31', '9999-12-31 23:59:59', '9999-12-31 23:59:59.999',
'9999-12-31'),
-> (13, '2024-01-01', '2024-01-01 10:00:00', '2024-01-01 10:00:00.123',
'2024-01-01'),
-> (14, NULL, NULL, NULL, NULL);
Query OK, 14 rows affected (0.09 sec)
{'label':'label_a4cceb5cea7e4c7e_a993c81827b1f5ed', 'status':'VISIBLE',
'txnId':'12017'}
mysql> SELECT
-> century('1989-03-21') as century_1989,
-> century('2000-01-01') as century_2000,
-> century('2001-01-01') as century_2001,
-> century('2015-07-14') as century_2015;
+--------------+--------------+--------------+--------------+
| century_1989 | century_2000 | century_2001 | century_2015 |
+--------------+--------------+--------------+--------------+
| 20 | 20 | 21 | 21 |
+--------------+--------------+--------------+--------------+
1 row in set (0.01 sec)
Co-authored-by: linrrarity <[email protected]>
---
be/src/vec/functions/date_time_transforms.h | 16 ++++
be/src/vec/functions/to_time_function.cpp | 7 +-
be/test/vec/function/function_time_test.cpp | 56 +++++++++++++
.../doris/catalog/BuiltinScalarFunctions.java | 2 +
.../executable/DateTimeExtractAndTransform.java | 15 ++++
.../expressions/functions/scalar/Century.java | 91 ++++++++++++++++++++++
.../expressions/visitor/ScalarFunctionVisitor.java | 5 ++
.../datetime_functions/test_date_function.out | 57 ++++++++++++++
.../datetime_functions/test_date_function.groovy | 27 +++++++
9 files changed, 275 insertions(+), 1 deletion(-)
diff --git a/be/src/vec/functions/date_time_transforms.h
b/be/src/vec/functions/date_time_transforms.h
index 89dffe288cf..ddce29e2446 100644
--- a/be/src/vec/functions/date_time_transforms.h
+++ b/be/src/vec/functions/date_time_transforms.h
@@ -74,6 +74,22 @@ namespace doris::vectorized {
#define TO_TIME_FUNCTION(CLASS, UNIT) TIME_FUNCTION_IMPL(CLASS, UNIT, UNIT())
TO_TIME_FUNCTION(ToYearImpl, year);
+template <PrimitiveType PType>
+struct ToCenturyImpl {
+ static constexpr PrimitiveType OpArgType = PType;
+ using NativeType = typename PrimitiveTypeTraits<PType>::CppNativeType;
+ static constexpr auto name = "century";
+
+ static inline auto execute(const NativeType& t) {
+ const auto& date_time_value = (typename
PrimitiveTypeTraits<PType>::CppType&)(t);
+ int year = date_time_value.year();
+ return (year - 1) / 100 + 1;
+ }
+
+ static DataTypes get_variadic_argument_types() {
+ return {std::make_shared<typename
PrimitiveTypeTraits<PType>::DataType>()};
+ }
+};
TO_TIME_FUNCTION(ToYearOfWeekImpl, year_of_week);
TO_TIME_FUNCTION(ToQuarterImpl, quarter);
TO_TIME_FUNCTION(ToMonthImpl, month);
diff --git a/be/src/vec/functions/to_time_function.cpp
b/be/src/vec/functions/to_time_function.cpp
index 68ed6126ca8..e930a42eb4b 100644
--- a/be/src/vec/functions/to_time_function.cpp
+++ b/be/src/vec/functions/to_time_function.cpp
@@ -66,7 +66,10 @@ using FunctionDateTimeV2Date =
FunctionDateOrDateTimeToSomething<DataTypeDateV2,
DateImpl<TYPE_DATETIMEV2>>;
using FunctionTimeStampV2 =
FunctionDateOrDateTimeToSomething<DataTypeDateTimeV2,
TimeStampImpl<TYPE_DATETIMEV2>>;
-
+using FunctionCenturyV2 =
+ FunctionDateOrDateTimeToSomething<DataTypeInt16,
ToCenturyImpl<TYPE_DATEV2>>;
+using FunctionDateTimeV2Century =
+ FunctionDateOrDateTimeToSomething<DataTypeInt16,
ToCenturyImpl<TYPE_DATETIMEV2>>;
void register_function_to_time_function(SimpleFunctionFactory& factory) {
factory.register_function<FunctionTimeStampV2>();
factory.register_function<FunctionSecondV2>();
@@ -92,6 +95,8 @@ void
register_function_to_time_function(SimpleFunctionFactory& factory) {
factory.register_function<FunctionDateTimeV2Quarter>();
factory.register_function<FunctionDateTimeV2ToDate>();
factory.register_function<FunctionDateTimeV2Date>();
+ factory.register_function<FunctionCenturyV2>();
+ factory.register_function<FunctionDateTimeV2Century>();
factory.register_alias("date", "datev2");
factory.register_alias("to_date", "to_datev2");
}
diff --git a/be/test/vec/function/function_time_test.cpp
b/be/test/vec/function/function_time_test.cpp
index 939117023c8..4ba2b16bdf5 100644
--- a/be/test/vec/function/function_time_test.cpp
+++ b/be/test/vec/function/function_time_test.cpp
@@ -87,7 +87,63 @@ TEST(VTimestampFunctionsTest, year_test) {
static_cast<void>(check_function<DataTypeInt16, true>(func_name,
input_types, data_set));
}
+TEST(VTimestampFunctionsTest, century_test) {
+ std::string func_name = "century";
+ InputTypeSet input_types = {PrimitiveType::TYPE_DATETIMEV2};
+
+ DataSet data_set = {{{std::string("2024-01-01 00:00:00")}, int16_t {21}},
+ {{std::string("2000-01-01 00:00:00")}, int16_t {20}},
+ {{std::string("1999-12-31 23:59:59")}, int16_t {20}},
+ {{std::string("1900-01-01 00:00:00")}, int16_t {19}},
+ {{std::string("1800-01-01 00:00:00")}, int16_t {18}},
+ {{std::string("1700-01-01 00:00:00")}, int16_t {17}},
+ {{std::string("1600-01-01 00:00:00")}, int16_t {16}},
+ {{std::string("1500-01-01 00:00:00")}, int16_t {15}},
+ {{std::string("1400-01-01 00:00:00")}, int16_t {14}},
+ {{std::string("1300-01-01 00:00:00")}, int16_t {13}},
+ {{std::string("1200-01-01 00:00:00")}, int16_t {12}},
+ {{std::string("1100-01-01 00:00:00")}, int16_t {11}},
+ {{std::string("1000-01-01 00:00:00")}, int16_t {10}},
+ {{std::string("0900-01-01 00:00:00")}, int16_t {9}},
+ {{std::string("0800-01-01 00:00:00")}, int16_t {8}},
+ {{std::string("0700-01-01 00:00:00")}, int16_t {7}},
+ {{std::string("0600-01-01 00:00:00")}, int16_t {6}},
+ {{std::string("0500-01-01 00:00:00")}, int16_t {5}},
+ {{std::string("0400-01-01 00:00:00")}, int16_t {4}},
+ {{std::string("0300-01-01 00:00:00")}, int16_t {3}},
+ {{std::string("0200-01-01 00:00:00")}, int16_t {2}},
+ {{std::string("0100-01-01 00:00:00")}, int16_t {1}},
+ {{std::string("0001-01-01 00:00:00")}, int16_t {1}}};
+
+ static_cast<void>(check_function<DataTypeInt16, true>(func_name,
input_types, data_set));
+}
+
+TEST(VTimestampFunctionsTest, century_v2_test) {
+ std::string func_name = "century";
+
+ {
+ InputTypeSet input_types = {PrimitiveType::TYPE_DATEV2};
+
+ DataSet data_set = {{{std::string("2024-01-01")}, int16_t {21}},
+ {{std::string("2000-01-01")}, int16_t {20}},
+ {{std::string("1900-01-01")}, int16_t {19}},
+ {{std::string("0001-01-01")}, int16_t {1}}};
+
+ static_cast<void>(check_function<DataTypeInt16, true>(func_name,
input_types, data_set));
+ }
+
+ {
+ InputTypeSet input_types = {PrimitiveType::TYPE_DATETIMEV2};
+
+ DataSet data_set = {{{std::string("2024-01-01 12:34:56")}, int16_t
{21}},
+ {{std::string("2000-01-01 12:34:56.789")}, int16_t
{20}},
+ {{std::string("1900-01-01 12:34:56.123456")},
int16_t {19}},
+ {{std::string("0001-01-01 00:00:00.000001")},
int16_t {1}}};
+
+ static_cast<void>(check_function<DataTypeInt16, true>(func_name,
input_types, data_set));
+ }
+}
TEST(VTimestampFunctionsTest, quarter_test) {
std::string func_name = "quarter";
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 c07bdb3bfe8..4a699f4cd17 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
@@ -130,6 +130,7 @@ import
org.apache.doris.nereids.trees.expressions.functions.scalar.BitmapXorCoun
import org.apache.doris.nereids.trees.expressions.functions.scalar.Cardinality;
import org.apache.doris.nereids.trees.expressions.functions.scalar.Cbrt;
import org.apache.doris.nereids.trees.expressions.functions.scalar.Ceil;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.Century;
import org.apache.doris.nereids.trees.expressions.functions.scalar.Char;
import
org.apache.doris.nereids.trees.expressions.functions.scalar.CharacterLength;
import org.apache.doris.nereids.trees.expressions.functions.scalar.Coalesce;
@@ -667,6 +668,7 @@ public class BuiltinScalarFunctions implements
FunctionHelper {
scalar(Cardinality.class, "array_size", "cardinality", "size"),
scalar(Cbrt.class, "cbrt"),
scalar(Ceil.class, "ceil", "ceiling"),
+ scalar(Century.class, "century"),
scalar(Char.class, "char"),
scalar(CharacterLength.class, "char_length", "character_length"),
scalar(Coalesce.class, "coalesce"),
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/executable/DateTimeExtractAndTransform.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/executable/DateTimeExtractAndTransform.java
index 120506221a8..3631d8e8b60 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/executable/DateTimeExtractAndTransform.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/executable/DateTimeExtractAndTransform.java
@@ -123,6 +123,21 @@ public class DateTimeExtractAndTransform {
return new SmallIntLiteral(((short) date.getYear()));
}
+
+ /**
+ * Executable datetime extract century
+ */
+ @ExecFunction(name = "century")
+ public static Expression century(DateV2Literal date) {
+ return new SmallIntLiteral((short) ((date.getYear() - 1) / 100 + 1));
+ }
+
+ @ExecFunction(name = "century")
+ public static Expression century(DateTimeV2Literal date) {
+ return new SmallIntLiteral((short) ((date.getYear() - 1) / 100 + 1));
+ }
+
+
/**
* Executable datetime extract quarter
*/
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Century.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Century.java
new file mode 100644
index 00000000000..9ed565d3d73
--- /dev/null
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Century.java
@@ -0,0 +1,91 @@
+// 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.PropagateNullable;
+import org.apache.doris.nereids.trees.expressions.shape.UnaryExpression;
+import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
+import org.apache.doris.nereids.types.DateTimeV2Type;
+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 'century'. This class is generated by GenerateFunction.
+ */
+public class Century extends ScalarFunction
+ implements UnaryExpression, ExplicitlyCastableSignature,
PropagateNullable, Monotonic {
+
+ private static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
+
FunctionSignature.ret(SmallIntType.INSTANCE).args(DateV2Type.INSTANCE),
+
FunctionSignature.ret(SmallIntType.INSTANCE).args(DateTimeV2Type.WILDCARD));
+
+ /**
+ * constructor with 1 argument.
+ */
+ public Century(Expression arg) {
+ super("century", arg);
+ }
+
+ /** constructor for withChildren and reuse signature */
+ private Century(ScalarFunctionParams functionParams) {
+ super(functionParams);
+ }
+
+ /**
+ * withChildren.
+ */
+ @Override
+ public Century withChildren(List<Expression> children) {
+ Preconditions.checkArgument(children.size() == 1);
+ return new Century(getFunctionParams(children));
+ }
+
+ @Override
+ public List<FunctionSignature> getSignatures() {
+ return SIGNATURES;
+ }
+
+ @Override
+ public <R, C> R accept(ExpressionVisitor<R, C> visitor, C context) {
+ return visitor.visitCentury(this, context);
+ }
+
+ @Override
+ public boolean isPositive() {
+ return true;
+ }
+
+ @Override
+ public int getMonotonicFunctionChildIndex() {
+ return 0;
+ }
+
+ @Override
+ public Expression withConstantArgs(Expression literal) {
+ return new Century(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 d907d0b6599..d97081cd747 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
@@ -141,6 +141,7 @@ import
org.apache.doris.nereids.trees.expressions.functions.scalar.BitmapXorCoun
import org.apache.doris.nereids.trees.expressions.functions.scalar.Cardinality;
import org.apache.doris.nereids.trees.expressions.functions.scalar.Cbrt;
import org.apache.doris.nereids.trees.expressions.functions.scalar.Ceil;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.Century;
import org.apache.doris.nereids.trees.expressions.functions.scalar.Char;
import
org.apache.doris.nereids.trees.expressions.functions.scalar.CharacterLength;
import org.apache.doris.nereids.trees.expressions.functions.scalar.Coalesce;
@@ -2506,6 +2507,10 @@ public interface ScalarFunctionVisitor<R, C> {
return visitScalarFunction(year, context);
}
+ default R visitCentury(Century century, C context) {
+ return visitScalarFunction(century, context);
+ }
+
default R visitYearOfWeek(YearOfWeek yearOfWeek, C context) {
return visitScalarFunction(yearOfWeek, 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 c9117deab3f..a0ec6218421 100644
---
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
@@ -446,6 +446,63 @@ February
2019-08-01T13:21:03 2019
9999-08-01T13:21:03 9999
+-- !sql --
+19
+
+-- !sql --
+20
+
+-- !sql --
+20
+
+-- !sql --
+21
+
+-- !sql --
+21
+
+-- !sql --
+1
+
+-- !sql --
+100
+
+-- !sql --
+20
+
+-- !sql --
+20
+
+-- !sql --
+20
+
+-- !sql --
+19
+
+-- !sql --
+19
+
+-- !sql --
+20
+
+-- !sql --
+21
+
+-- !sql --
+21
+
+-- !sql --
+22
+
+-- !sql --
+\N
+
+-- !sql --
+\N
+
+-- !sql --
+\N
+
-- !sql --
1987
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 c7223d076a7..69c56866832 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
@@ -544,6 +544,33 @@ 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 """
+ // CENTURY
+ qt_sql """ select century('1900-01-01') """
+ qt_sql """ select century('1901-01-01') """
+ qt_sql """ select century('2000-01-01') """
+ qt_sql """ select century('2001-01-01') """
+ qt_sql """ select century('2023-12-31') """
+ qt_sql """ select century('0001-01-01') """
+ qt_sql """ select century('9999-12-31') """
+ qt_sql """ select century('1999-12-31 23:59:59') """
+ qt_sql """ select century(cast('2000-01-01' as date)) """
+ qt_sql """ select century(cast('2000-01-01 12:00:00' as datetime)) """
+
+ // Test century with different date formats
+ qt_sql """ select century('1900-12-31') """ // 19th century
+ qt_sql """ select century('1899-12-31') """ // 19th century
+ qt_sql """ select century('2000-12-31') """ // 20th century
+ qt_sql """ select century('2001-01-01') """ // 21st century
+ qt_sql """ select century('2100-01-01') """ // 21st century
+ qt_sql """ select century('2101-01-01') """ // 22nd century
+
+ // Test century with NULL values
+ qt_sql """ select century(NULL) """
+
+ // Test century with invalid dates
+ qt_sql """ select century('0000-00-00') """
+ qt_sql """ select century('2023-13-45') """
+
// YEAROFWEEK
qt_sql """ select year_of_week('1987-01-01') """
qt_sql """ select year_of_week('2050-01-01') """
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]