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 ef2667bc78b [feat](func) Support CURTIME with precision (#56665)
ef2667bc78b is described below

commit ef2667bc78b78426a7be3d4cc9112ce4c3459d7c
Author: linrrarity <[email protected]>
AuthorDate: Fri Oct 10 17:40:58 2025 +0800

    [feat](func) Support CURTIME with precision (#56665)
    
    ### What problem does this PR solve?
    
    Issue Number: #48203
    
    Related PR: #xxx
    
    Problem Summary:
    
    ```text
    mysql> select curtime(5);
    +----------------+
    | curtime(5)     |
    +----------------+
    | 12:52:30.77164 |
    +----------------+
    
    mysql> select curtime(114514);
    ERROR 1105 (HY000): errCode = 2, detailMessage = Can not find the 
compatibility function signature: current_time(INT)
    mysql> SELECT CURTIME(7);
    ERROR 1105 (HY000): errCode = 2, detailMessage = The precision must be 
between 0 and 6
    ```
---
 .../function_date_or_datetime_computation.h        | 25 ++++++-
 be/test/vec/function/function_time_test.cpp        | 83 ++++++++++++++++++++++
 .../functions/executable/DateTimeAcquire.java      | 11 +++
 .../expressions/functions/scalar/CurrentTime.java  | 47 ++++++++++--
 .../trees/expressions/literal/TimeV2Literal.java   | 12 ++++
 .../datetime_functions/test_date_function.groovy   | 16 +++++
 6 files changed, 188 insertions(+), 6 deletions(-)

diff --git a/be/src/vec/functions/function_date_or_datetime_computation.h 
b/be/src/vec/functions/function_date_or_datetime_computation.h
index 5cf5158a1eb..65c116b0cb7 100644
--- a/be/src/vec/functions/function_date_or_datetime_computation.h
+++ b/be/src/vec/functions/function_date_or_datetime_computation.h
@@ -838,10 +838,31 @@ struct CurrentTimeImpl {
     static Status execute(FunctionContext* context, Block& block, const 
ColumnNumbers& arguments,
                           uint32_t result, size_t input_rows_count) {
         auto col_to = ColumnTimeV2::create();
-        VecDateTimeValue dtv;
+        DateV2Value<DateTimeV2ValueType> dtv;
         dtv.from_unixtime(context->state()->timestamp_ms() / 1000,
                           context->state()->timezone_obj());
-        auto time = TimeValue::make_time(dtv.hour(), dtv.minute(), 
dtv.second());
+        double time;
+        if (arguments.size() == 1) {
+            // the precision must be const, which is checked in fe.
+            const auto* col = assert_cast<const ColumnInt8*>(
+                    block.get_by_position(arguments[0]).column.get());
+            uint8_t precision = col->get_element(0);
+            if (precision <= 6) {
+                dtv.from_unixtime(context->state()->timestamp_ms() / 1000,
+                                  context->state()->nano_seconds(),
+                                  context->state()->timezone_obj(), precision);
+                time = TimeValue::make_time(dtv.hour(), dtv.minute(), 
dtv.second(),
+                                            dtv.microsecond());
+            } else {
+                return Status::InvalidArgument(
+                        "The precision in function CURTIME should be between 0 
and 6, but got {}",
+                        precision);
+            }
+        } else {
+            dtv.from_unixtime(context->state()->timestamp_ms() / 1000,
+                              context->state()->timezone_obj());
+            time = TimeValue::make_time(dtv.hour(), dtv.minute(), 
dtv.second());
+        }
         col_to->insert_value(time);
         block.get_by_position(result).column =
                 ColumnConst::create(std::move(col_to), input_rows_count);
diff --git a/be/test/vec/function/function_time_test.cpp 
b/be/test/vec/function/function_time_test.cpp
index 6368859ab55..7b88ecdf1b4 100644
--- a/be/test/vec/function/function_time_test.cpp
+++ b/be/test/vec/function/function_time_test.cpp
@@ -1558,4 +1558,87 @@ TEST(VTimestampFunctionsTest, time) {
     static_cast<void>(check_function<DataTypeTimeV2, true>(func_name, 
input_types, data_set));
 }
 
+TEST(VTimestampFunctionsTest, curtime_test) {
+    std::string func_name = "curtime";
+
+    // Test curtime without precision
+    {
+        InputTypeSet input_types = {};
+        Block block;
+        ColumnsWithTypeAndName arguments;
+
+        auto return_type = std::make_shared<DataTypeTimeV2>(0);
+        FunctionBasePtr func =
+                SimpleFunctionFactory::instance().get_function(func_name, 
arguments, return_type);
+        EXPECT_TRUE(func != nullptr);
+
+        auto fn_ctx_return = std::make_shared<DataTypeTimeV2>(0);
+        std::vector<DataTypePtr> arg_types = {};
+        FunctionUtils fn_utils(fn_ctx_return, arg_types, false);
+        auto* fn_ctx = fn_utils.get_fn_ctx();
+
+        EXPECT_TRUE(func->open(fn_ctx, FunctionContext::FRAGMENT_LOCAL).ok());
+        EXPECT_TRUE(func->open(fn_ctx, FunctionContext::THREAD_LOCAL).ok());
+
+        block.insert({nullptr, return_type, "result"});
+        ColumnNumbers args;
+        auto st = func->execute(fn_ctx, block, args, 0, 1);
+        EXPECT_TRUE(st.ok());
+
+        auto result_col = block.get_by_position(0).column;
+        EXPECT_TRUE(result_col);
+        if (const auto* const_col = 
check_and_get_column<ColumnConst>(result_col.get())) {
+            auto time_value = const_col->get_field().get<double>();
+            EXPECT_GE(time_value, 0.0);
+            EXPECT_LE(time_value, 24.0 * 3600 * 1000000);
+        }
+
+        EXPECT_TRUE(func->close(fn_ctx, FunctionContext::THREAD_LOCAL).ok());
+        EXPECT_TRUE(func->close(fn_ctx, FunctionContext::FRAGMENT_LOCAL).ok());
+    }
+
+    // Test curtime with precision
+    {
+        InputTypeSet input_types = {PrimitiveType::TYPE_TINYINT};
+        Block block;
+
+        auto precision_col = ColumnInt8::create();
+        precision_col->insert_value(3);
+        auto precision_type = std::make_shared<DataTypeInt8>();
+        block.insert({std::move(precision_col), precision_type, "precision"});
+
+        ColumnsWithTypeAndName arguments;
+        arguments.push_back(block.get_by_position(0));
+
+        auto return_type = std::make_shared<DataTypeTimeV2>(3);
+        FunctionBasePtr func =
+                SimpleFunctionFactory::instance().get_function(func_name, 
arguments, return_type);
+        EXPECT_TRUE(func != nullptr);
+
+        auto fn_ctx_return = std::make_shared<DataTypeTimeV2>(3);
+        std::vector<DataTypePtr> arg_types = {precision_type};
+        FunctionUtils fn_utils(fn_ctx_return, arg_types, false);
+        auto* fn_ctx = fn_utils.get_fn_ctx();
+
+        EXPECT_TRUE(func->open(fn_ctx, FunctionContext::FRAGMENT_LOCAL).ok());
+        EXPECT_TRUE(func->open(fn_ctx, FunctionContext::THREAD_LOCAL).ok());
+
+        block.insert({nullptr, return_type, "result"});
+        ColumnNumbers args = {0};
+        auto st = func->execute(fn_ctx, block, args, 1, 1);
+        EXPECT_TRUE(st.ok());
+
+        auto result_col = block.get_by_position(1).column;
+        EXPECT_TRUE(result_col);
+        if (const auto* const_col = 
check_and_get_column<ColumnConst>(result_col.get())) {
+            auto time_value = const_col->get_field().get<double>();
+            EXPECT_GE(time_value, 0.0);
+            EXPECT_LE(time_value, 24.0 * 3600 * 1000000);
+        }
+
+        EXPECT_TRUE(func->close(fn_ctx, FunctionContext::THREAD_LOCAL).ok());
+        EXPECT_TRUE(func->close(fn_ctx, FunctionContext::FRAGMENT_LOCAL).ok());
+    }
+}
+
 } // namespace doris::vectorized
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/executable/DateTimeAcquire.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/executable/DateTimeAcquire.java
index cd8b2257c6e..a6d12f8f015 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/executable/DateTimeAcquire.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/executable/DateTimeAcquire.java
@@ -24,6 +24,7 @@ import 
org.apache.doris.nereids.trees.expressions.literal.DateTimeV2Literal;
 import org.apache.doris.nereids.trees.expressions.literal.DateV2Literal;
 import org.apache.doris.nereids.trees.expressions.literal.IntegerLiteral;
 import org.apache.doris.nereids.trees.expressions.literal.TimeV2Literal;
+import org.apache.doris.nereids.trees.expressions.literal.TinyIntLiteral;
 import org.apache.doris.nereids.util.DateUtils;
 
 import java.time.LocalDateTime;
@@ -95,11 +96,21 @@ public class DateTimeAcquire {
         return 
TimeV2Literal.fromJavaDateType(LocalDateTime.now(DateUtils.getTimeZone()));
     }
 
+    @ExecFunction(name = "curtime")
+    public static Expression curTime(TinyIntLiteral precision) {
+        return 
TimeV2Literal.fromJavaDateType(LocalDateTime.now(DateUtils.getTimeZone()), 
precision.getValue());
+    }
+
     @ExecFunction(name = "current_time")
     public static Expression currentTime() {
         return 
TimeV2Literal.fromJavaDateType(LocalDateTime.now(DateUtils.getTimeZone()));
     }
 
+    @ExecFunction(name = "current_time")
+    public static Expression currentTime(TinyIntLiteral precision) {
+        return 
TimeV2Literal.fromJavaDateType(LocalDateTime.now(DateUtils.getTimeZone()), 
precision.getValue());
+    }
+
     /**
      * date transformation function: unix_timestamp
      */
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/CurrentTime.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/CurrentTime.java
index 0b640089569..454294727aa 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/CurrentTime.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/CurrentTime.java
@@ -18,12 +18,16 @@
 package org.apache.doris.nereids.trees.expressions.functions.scalar;
 
 import org.apache.doris.catalog.FunctionSignature;
+import org.apache.doris.nereids.exceptions.AnalysisException;
 import org.apache.doris.nereids.trees.expressions.Expression;
 import org.apache.doris.nereids.trees.expressions.functions.AlwaysNotNullable;
-import 
org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSignature;
+import org.apache.doris.nereids.trees.expressions.functions.ComputeSignature;
+import 
org.apache.doris.nereids.trees.expressions.functions.ImplicitlyCastableSignature;
+import org.apache.doris.nereids.trees.expressions.literal.TinyIntLiteral;
 import org.apache.doris.nereids.trees.expressions.shape.LeafExpression;
 import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
 import org.apache.doris.nereids.types.TimeV2Type;
+import org.apache.doris.nereids.types.TinyIntType;
 
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
@@ -34,10 +38,11 @@ import java.util.List;
  * ScalarFunction 'current_time'. This class is generated by GenerateFunction.
  */
 public class CurrentTime extends ScalarFunction
-        implements LeafExpression, ExplicitlyCastableSignature, 
AlwaysNotNullable {
+        implements LeafExpression, ImplicitlyCastableSignature, 
AlwaysNotNullable, ComputeSignature {
 
     public static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
-            FunctionSignature.ret(TimeV2Type.INSTANCE).args()
+            FunctionSignature.ret(TimeV2Type.INSTANCE).args(),
+            
FunctionSignature.ret(TimeV2Type.INSTANCE).args(TinyIntType.INSTANCE)
     );
 
     /**
@@ -47,17 +52,51 @@ public class CurrentTime extends ScalarFunction
         super("current_time");
     }
 
+    /**
+     * constructor with 1 argument.
+     */
+    public CurrentTime(Expression arg) {
+        super("current_time", arg);
+    }
+
     /** constructor for withChildren and reuse signature */
     private CurrentTime(ScalarFunctionParams functionParams) {
         super(functionParams);
     }
 
+    @Override
+    public FunctionSignature computeSignature(FunctionSignature signature) {
+        if (arity() == 1 && child(0) instanceof TinyIntLiteral) {
+            byte precision = ((TinyIntLiteral) child(0)).getValue();
+            if (precision < 0 || precision > 6) {
+                throw new IllegalArgumentException("The precision must be 
between 0 and 6");
+            }
+            return 
FunctionSignature.ret(TimeV2Type.of(precision)).args(TinyIntType.INSTANCE);
+        }
+
+        return super.computeSignature(signature);
+    }
+
     @Override
     public Expression withChildren(List<Expression> children) {
-        Preconditions.checkArgument(children.isEmpty());
+        Preconditions.checkArgument(children.isEmpty() || children.size() == 
1);
         return new CurrentTime(getFunctionParams(children));
     }
 
+    @Override
+    public void checkLegalityAfterRewrite() {
+        if (arity() == 1) {
+            if (!child(0).isLiteral()) {
+                throw new AnalysisException("CURTIME only accepts literal as 
precision.");
+            }
+        }
+    }
+
+    @Override
+    public void checkLegalityBeforeTypeCoercion() {
+        checkLegalityAfterRewrite();
+    }
+
     @Override
     public List<FunctionSignature> getSignatures() {
         return SIGNATURES;
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/TimeV2Literal.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/TimeV2Literal.java
index 538052d9ad7..e697ef2b2e7 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/TimeV2Literal.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/TimeV2Literal.java
@@ -301,6 +301,18 @@ public class TimeV2Literal extends Literal {
         return new TimeV2Literal(dateTime.getHour(), dateTime.getMinute(), 
dateTime.getSecond(), 0, 0, false);
     }
 
+    /**
+     *  construct with precision
+     */
+    public static Expression fromJavaDateType(LocalDateTime dateTime, int 
precision) {
+        if (isDateOutOfRange(dateTime)) {
+            throw new AnalysisException("datetime out of range" + 
dateTime.toString());
+        }
+        int value = (int) Math.pow(10, TimeV2Type.MAX_SCALE - precision);
+        return new TimeV2Literal(dateTime.getHour(), dateTime.getMinute(), 
dateTime.getSecond(),
+                (dateTime.getNano() / 1000) / value * value, precision, false);
+    }
+
     public LocalDateTime toJavaDateType() {
         return LocalDateTime.of(0, 1, 1, ((int) getHour()), ((int) 
getMinute()), ((int) getSecond()),
                 (int) getMicroSecond() * 1000);
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 50369ce3395..d3920031ef0 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
@@ -226,6 +226,22 @@ suite("test_date_function") {
     // TIME CURTIME()
     def curtime_result = sql """ SELECT CURTIME() """
     assertTrue(curtime_result[0].size() == 1)
+    def curtime_with_arg = sql """ SELECT CAST(CURTIME(3) AS STRING) """
+    assertTrue(curtime_with_arg[0].size() == 1)
+    assertTrue(curtime_with_arg[0][0].contains('.'))
+
+    curtime_with_arg = sql """ SELECT CAST(CURTIME(0) AS STRING) """
+    assertTrue(curtime_with_arg[0].size() == 1)
+    assertFalse(curtime_with_arg[0][0].contains('.'))
+
+    test {
+        sql """ SELECT CURTIME(114514);"""
+        exception "Can not find the compatibility function signature: 
current_time(INT)"
+    }
+    test {
+        sql """ SELECT CURTIME(7); """
+        exception "The precision must be between 0 and 6"
+    }
 
     sql """ insert into ${tableName} values ("2010-11-30 23:59:59") """
     // DATE_ADD


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to