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]