From b5fdab0eb742770bf009f08acf520f0345ad8aea Mon Sep 17 00:00:00 2001 From: qzr <3302371508@qq.com> Date: Sun, 29 Mar 2026 10:28:22 +0800 Subject: [PATCH 1/3] feat(be): add human_readable_seconds implementation --- be/src/exprs/function/function_utility.cpp | 116 +++++++++++++++++++++ 1 file changed, 116 insertions(+) diff --git a/be/src/exprs/function/function_utility.cpp b/be/src/exprs/function/function_utility.cpp index 340f05ab0c4fd7..83678d0292088f 100644 --- a/be/src/exprs/function/function_utility.cpp +++ b/be/src/exprs/function/function_utility.cpp @@ -20,10 +20,13 @@ // IWYU pragma: no_include #include #include // IWYU pragma: keep +#include +#include #include #include #include #include +#include #include "common/status.h" #include "core/assert_cast.h" @@ -138,11 +141,124 @@ class FunctionVersion : public IFunction { } }; +class FunctionHumanReadableSeconds : public IFunction { +public: + static constexpr auto name = "human_readable_seconds"; + + static FunctionPtr create() { return std::make_shared(); } + + String get_name() const override { return name; } + + size_t get_number_of_arguments() const override { return 1; } + + DataTypePtr get_return_type_impl(const DataTypes& /*arguments*/) const override { + return std::make_shared(); + } + + Status execute_impl(FunctionContext* /*context*/, Block& block, const ColumnNumbers& arguments, + uint32_t result, size_t input_rows_count) const override { + const auto& argument_column = + block.get_by_position(arguments[0]).column->convert_to_full_column_if_const(); + const auto* data_column = check_and_get_column(*argument_column); + if (data_column == nullptr) { + return Status::InvalidArgument("Illegal column {} of first argument of function {}", + argument_column->get_name(), name); + } + + auto result_column = ColumnString::create(); + for (size_t i = 0; i < input_rows_count; ++i) { + auto value = data_column->get_element(i); + auto text = _to_human_readable(value); + result_column->insert_data(text.data(), text.size()); + } + + block.replace_by_position(result, std::move(result_column)); + return Status::OK(); + } + +private: + static std::string _append_unit(int64_t value, const char* singular, const char* plural) { + return std::to_string(value) + " " + (value == 1 ? singular : plural); + } + + static std::string _to_human_readable(double seconds) { + if (std::isnan(seconds)) { + return "nan"; + } + if (std::isinf(seconds)) { + return seconds > 0 ? "inf" : "-inf"; + } + + bool negative = seconds < 0; + double abs_seconds = std::fabs(seconds); + if (abs_seconds >= static_cast(std::numeric_limits::max())) { + abs_seconds = static_cast(std::numeric_limits::max()); + } + + double integral_part = 0; + double fractional_part = std::modf(abs_seconds, &integral_part); + int64_t remain = static_cast(integral_part); + int64_t millis = static_cast(std::llround(fractional_part * 1000.0)); + if (millis == 1000) { + ++remain; + millis = 0; + } + constexpr int64_t WEEK = 7 * 24 * 60 * 60; + constexpr int64_t DAY = 24 * 60 * 60; + constexpr int64_t HOUR = 60 * 60; + constexpr int64_t MINUTE = 60; + + const int64_t weeks = remain / WEEK; + remain %= WEEK; + const int64_t days = remain / DAY; + remain %= DAY; + const int64_t hours = remain / HOUR; + remain %= HOUR; + const int64_t minutes = remain / MINUTE; + const int64_t secs = remain % MINUTE; + + std::vector parts; + parts.reserve(5); + if (weeks > 0) { + parts.emplace_back(_append_unit(weeks, "week", "weeks")); + } + if (days > 0) { + parts.emplace_back(_append_unit(days, "day", "days")); + } + if (hours > 0) { + parts.emplace_back(_append_unit(hours, "hour", "hours")); + } + if (minutes > 0) { + parts.emplace_back(_append_unit(minutes, "minute", "minutes")); + } + if (secs > 0 || (parts.empty() && millis == 0)) { + parts.emplace_back(_append_unit(secs, "second", "seconds")); + } + if (millis > 0) { + parts.emplace_back(_append_unit(millis, "millisecond", "milliseconds")); + } + + std::string result; + if (negative && + (weeks > 0 || days > 0 || hours > 0 || minutes > 0 || secs > 0 || millis > 0)) { + result.push_back('-'); + } + for (size_t i = 0; i < parts.size(); ++i) { + if (i != 0) { + result += ", "; + } + result += parts[i]; + } + return result; + } +}; + const std::string FunctionVersion::version = "5.7.99"; void register_function_utility(SimpleFunctionFactory& factory) { factory.register_function(); factory.register_function(); + factory.register_function(); } } // namespace doris From a83b97911772d164e61512d27fc333229ea5921a Mon Sep 17 00:00:00 2001 From: qzr <3302371508@qq.com> Date: Sun, 29 Mar 2026 10:28:48 +0800 Subject: [PATCH 2/3] feat(fe): register human_readable_seconds and add constant folding --- .../doris/catalog/BuiltinScalarFunctions.java | 2 + .../DateTimeExtractAndTransform.java | 82 +++++++++++++++++++ .../scalar/HumanReadableSeconds.java | 68 +++++++++++++++ .../visitor/ScalarFunctionVisitor.java | 5 ++ 4 files changed, 157 insertions(+) create mode 100644 fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/HumanReadableSeconds.java 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 c8719dbaeb5832..46c59f378a4674 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 @@ -250,6 +250,7 @@ import org.apache.doris.nereids.trees.expressions.functions.scalar.HoursAdd; import org.apache.doris.nereids.trees.expressions.functions.scalar.HoursDiff; import org.apache.doris.nereids.trees.expressions.functions.scalar.HoursSub; +import org.apache.doris.nereids.trees.expressions.functions.scalar.HumanReadableSeconds; import org.apache.doris.nereids.trees.expressions.functions.scalar.If; import org.apache.doris.nereids.trees.expressions.functions.scalar.Ignore; import org.apache.doris.nereids.trees.expressions.functions.scalar.Initcap; @@ -802,6 +803,7 @@ public class BuiltinScalarFunctions implements FunctionHelper { scalar(HllFromBase64.class, "hll_from_base64"), scalar(HllHash.class, "hll_hash"), scalar(HllToBase64.class, "hll_to_base64"), + scalar(HumanReadableSeconds.class, "human_readable_seconds"), scalar(Hour.class, "hour"), scalar(HourCeil.class, "hour_ceil"), scalar(HourFloor.class, "hour_floor"), 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 acbdfc255047e3..db4a667fa4d726 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 @@ -33,6 +33,7 @@ import org.apache.doris.nereids.trees.expressions.literal.DoubleLiteral; import org.apache.doris.nereids.trees.expressions.literal.IntegerLiteral; import org.apache.doris.nereids.trees.expressions.literal.NullLiteral; +import org.apache.doris.nereids.trees.expressions.literal.NumericLiteral; import org.apache.doris.nereids.trees.expressions.literal.SmallIntLiteral; import org.apache.doris.nereids.trees.expressions.literal.StringLikeLiteral; import org.apache.doris.nereids.trees.expressions.literal.StringLiteral; @@ -67,7 +68,9 @@ import java.time.format.TextStyle; import java.time.temporal.ChronoUnit; import java.time.temporal.WeekFields; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Locale; /** @@ -1340,6 +1343,85 @@ public static Expression secToTime(DoubleLiteral sec) { return new TimeV2Literal(sec.getValue() * 1000000); } + /** + * human_readable_seconds function for constant folding + */ + @ExecFunction(name = "human_readable_seconds") + public static Expression humanReadableSeconds(NumericLiteral sec) { + return new VarcharLiteral(formatHumanReadableSeconds(sec.getDouble())); + } + + private static String formatHumanReadableSeconds(double seconds) { + if (Double.isNaN(seconds)) { + return "nan"; + } + if (Double.isInfinite(seconds)) { + return seconds > 0 ? "inf" : "-inf"; + } + + boolean negative = seconds < 0; + double absSeconds = Math.abs(seconds); + if (absSeconds >= (double) Long.MAX_VALUE) { + absSeconds = (double) Long.MAX_VALUE; + } + + long remain = (long) absSeconds; + long millis = Math.round((absSeconds - remain) * 1000.0d); + if (millis == 1000) { + remain++; + millis = 0; + } + final long week = 7L * 24 * 60 * 60; + final long day = 24L * 60 * 60; + final long hour = 60L * 60; + final long minute = 60L; + + long weeks = remain / week; + remain %= week; + long days = remain / day; + remain %= day; + long hours = remain / hour; + remain %= hour; + long minutes = remain / minute; + long secs = remain % minute; + + List parts = new ArrayList<>(5); + if (weeks > 0) { + parts.add(formatUnit(weeks, "week", "weeks")); + } + if (days > 0) { + parts.add(formatUnit(days, "day", "days")); + } + if (hours > 0) { + parts.add(formatUnit(hours, "hour", "hours")); + } + if (minutes > 0) { + parts.add(formatUnit(minutes, "minute", "minutes")); + } + if (secs > 0 || (parts.isEmpty() && millis == 0)) { + parts.add(formatUnit(secs, "second", "seconds")); + } + if (millis > 0) { + parts.add(formatUnit(millis, "millisecond", "milliseconds")); + } + + StringBuilder result = new StringBuilder(); + if (negative && (weeks > 0 || days > 0 || hours > 0 || minutes > 0 || secs > 0 || millis > 0)) { + result.append('-'); + } + for (int i = 0; i < parts.size(); i++) { + if (i > 0) { + result.append(", "); + } + result.append(parts.get(i)); + } + return result.toString(); + } + + private static String formatUnit(long value, String singular, String plural) { + return value + " " + (value == 1 ? singular : plural); + } + /** * get_format function for constant folding */ diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/HumanReadableSeconds.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/HumanReadableSeconds.java new file mode 100644 index 00000000000000..e73b96ed4a202b --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/HumanReadableSeconds.java @@ -0,0 +1,68 @@ +// 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.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.DoubleType; +import org.apache.doris.nereids.types.VarcharType; + +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; + +import java.util.List; + +/** + * ScalarFunction 'human_readable_seconds'. + */ +public class HumanReadableSeconds extends ScalarFunction + implements UnaryExpression, ExplicitlyCastableSignature, PropagateNullable { + + public static final List SIGNATURES = ImmutableList.of( + FunctionSignature.ret(VarcharType.SYSTEM_DEFAULT).args(DoubleType.INSTANCE) + ); + + public HumanReadableSeconds(Expression arg) { + super("human_readable_seconds", arg); + } + + /** constructor for withChildren and reuse signature */ + private HumanReadableSeconds(ScalarFunctionParams functionParams) { + super(functionParams); + } + + @Override + public HumanReadableSeconds withChildren(List children) { + Preconditions.checkArgument(children.size() == 1); + return new HumanReadableSeconds(getFunctionParams(children)); + } + + @Override + public List getSignatures() { + return SIGNATURES; + } + + @Override + public R accept(ExpressionVisitor visitor, C context) { + return visitor.visitHumanReadableSeconds(this, context); + } +} 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 c32d2157d50c50..c041a318a3f81e 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 @@ -270,6 +270,7 @@ import org.apache.doris.nereids.trees.expressions.functions.scalar.HoursAdd; import org.apache.doris.nereids.trees.expressions.functions.scalar.HoursDiff; import org.apache.doris.nereids.trees.expressions.functions.scalar.HoursSub; +import org.apache.doris.nereids.trees.expressions.functions.scalar.HumanReadableSeconds; import org.apache.doris.nereids.trees.expressions.functions.scalar.If; import org.apache.doris.nereids.trees.expressions.functions.scalar.Ignore; import org.apache.doris.nereids.trees.expressions.functions.scalar.Initcap; @@ -1568,6 +1569,10 @@ default R visitHllToBase64(HllToBase64 hllToBase64, C context) { return visitScalarFunction(hllToBase64, context); } + default R visitHumanReadableSeconds(HumanReadableSeconds humanReadableSeconds, C context) { + return visitScalarFunction(humanReadableSeconds, context); + } + default R visitHour(Hour hour, C context) { return visitScalarFunction(hour, context); } From f00fad44386aa632669c8d2a77bc9bd19d1520cf Mon Sep 17 00:00:00 2001 From: qzr <3302371508@qq.com> Date: Sun, 29 Mar 2026 10:28:58 +0800 Subject: [PATCH 3/3] test: add BE/FE UT and regression cases for human_readable_seconds --- .../function_human_readable_seconds_test.cpp | 53 ++++++++++++++ .../DateTimeExtractAndTransformTest.java | 12 +++ .../timestamp/TestHumanReadableSeconds.out | 12 +++ .../test_human_readable_seconds.out | 73 +++++++++++++++++++ .../timestamp/TestHumanReadableSeconds.sql | 8 +- .../test_human_readable_seconds.groovy | 60 +++++++++++++++ 6 files changed, 214 insertions(+), 4 deletions(-) create mode 100644 be/test/exprs/function/function_human_readable_seconds_test.cpp create mode 100644 regression-test/data/query_p0/sql_functions/datetime_functions/test_human_readable_seconds.out create mode 100644 regression-test/suites/query_p0/sql_functions/datetime_functions/test_human_readable_seconds.groovy diff --git a/be/test/exprs/function/function_human_readable_seconds_test.cpp b/be/test/exprs/function/function_human_readable_seconds_test.cpp new file mode 100644 index 00000000000000..5c9a2607092afe --- /dev/null +++ b/be/test/exprs/function/function_human_readable_seconds_test.cpp @@ -0,0 +1,53 @@ +// 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. + +#include +#include + +#include "core/data_type/data_type_string.h" +#include "core/types.h" +#include "exprs/function/function_test_util.h" + +namespace doris { +using namespace ut_type; + +TEST(FunctionHumanReadableSecondsTest, one_arg) { + std::string func_name = "human_readable_seconds"; + + InputTypeSet input_types = {PrimitiveType::TYPE_DOUBLE}; + + DataSet data_set = { + {{96.0}, std::string("1 minute, 36 seconds")}, + {{3762.0}, std::string("1 hour, 2 minutes, 42 seconds")}, + {{56363463.0}, std::string("93 weeks, 1 day, 8 hours, 31 minutes, 3 seconds")}, + {{0.0}, std::string("0 seconds")}, + {{-96.0}, std::string("-1 minute, 36 seconds")}, + {{0.9}, std::string("900 milliseconds")}, + {{0.001}, std::string("1 millisecond")}, + {{1.001}, std::string("1 second, 1 millisecond")}, + {{475.33}, std::string("7 minutes, 55 seconds, 330 milliseconds")}, + {{-0.5}, std::string("-500 milliseconds")}, + {{1.2}, std::string("1 second")}, + {{std::numeric_limits::infinity()}, std::string("inf")}, + {{-std::numeric_limits::infinity()}, std::string("-inf")}, + {{std::numeric_limits::quiet_NaN()}, std::string("nan")}, + {{Null()}, Null()}}; + + check_function_all_arg_comb(func_name, input_types, data_set); +} + +} // namespace doris diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/functions/executable/DateTimeExtractAndTransformTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/functions/executable/DateTimeExtractAndTransformTest.java index ee3604f83dee51..a096d506667eaa 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/functions/executable/DateTimeExtractAndTransformTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/functions/executable/DateTimeExtractAndTransformTest.java @@ -21,9 +21,11 @@ import org.apache.doris.nereids.trees.expressions.literal.BigIntLiteral; import org.apache.doris.nereids.trees.expressions.literal.DateTimeV2Literal; import org.apache.doris.nereids.trees.expressions.literal.DecimalV3Literal; +import org.apache.doris.nereids.trees.expressions.literal.DoubleLiteral; import org.apache.doris.nereids.trees.expressions.literal.SmallIntLiteral; import org.apache.doris.nereids.trees.expressions.literal.StringLiteral; import org.apache.doris.nereids.trees.expressions.literal.TinyIntLiteral; +import org.apache.doris.nereids.trees.expressions.literal.VarcharLiteral; import org.apache.doris.nereids.types.DateTimeV2Type; import org.junit.jupiter.api.Assertions; @@ -166,4 +168,14 @@ public void testFromUnixTimeOutOfRangeThrows() { Assertions.assertThrows(AnalysisException.class, () -> DateTimeExtractAndTransform.fromUnixTime(dec)); } + + @Test + void testHumanReadableSecondsWithMilliseconds() { + Assertions.assertEquals(new VarcharLiteral("7 minutes, 55 seconds, 330 milliseconds"), + DateTimeExtractAndTransform.humanReadableSeconds(new DoubleLiteral(475.33))); + Assertions.assertEquals(new VarcharLiteral("900 milliseconds"), + DateTimeExtractAndTransform.humanReadableSeconds(new DoubleLiteral(0.9))); + Assertions.assertEquals(new VarcharLiteral("-500 milliseconds"), + DateTimeExtractAndTransform.humanReadableSeconds(new DoubleLiteral(-0.5))); + } } diff --git a/regression-test/data/external_table_p0/dialect_compatible/sql/presto/scalar/timestamp/TestHumanReadableSeconds.out b/regression-test/data/external_table_p0/dialect_compatible/sql/presto/scalar/timestamp/TestHumanReadableSeconds.out index 420e711e026da7..fc7002983bf8ed 100644 --- a/regression-test/data/external_table_p0/dialect_compatible/sql/presto/scalar/timestamp/TestHumanReadableSeconds.out +++ b/regression-test/data/external_table_p0/dialect_compatible/sql/presto/scalar/timestamp/TestHumanReadableSeconds.out @@ -9,5 +9,17 @@ 0 -- !TestHumanReadableSeconds_4 -- +6 days, 4 hours, 42 minutes, 13 seconds, 951 milliseconds + +-- !TestHumanReadableSeconds_5 -- +6 days, 4 hours, 42 minutes, 13 seconds, 251 milliseconds + +-- !TestHumanReadableSeconds_6 -- 0 +-- !TestHumanReadableSeconds_7 -- +6 days, 4 hours, 42 minutes, 13 seconds, 951 milliseconds + +-- !TestHumanReadableSeconds_8 -- +6 days, 4 hours, 42 minutes, 13 seconds, 251 milliseconds + diff --git a/regression-test/data/query_p0/sql_functions/datetime_functions/test_human_readable_seconds.out b/regression-test/data/query_p0/sql_functions/datetime_functions/test_human_readable_seconds.out new file mode 100644 index 00000000000000..87a7039a5e8974 --- /dev/null +++ b/regression-test/data/query_p0/sql_functions/datetime_functions/test_human_readable_seconds.out @@ -0,0 +1,73 @@ +-- This file is automatically generated. You should know what you did if you want to edit this +-- !empty_nullable -- + +-- !empty_not_nullable -- + +-- !all_null -- +\N +\N +\N + +-- !nullable -- +1 minute, 36 seconds +1 hour, 2 minutes, 42 seconds +93 weeks, 1 day, 8 hours, 31 minutes, 3 seconds +0 seconds +-1 minute, 36 seconds +900 milliseconds +1 second, 200 milliseconds +1 minute, 1 second +1 week +\N + +-- !not_nullable -- +1 minute, 36 seconds +1 hour, 2 minutes, 42 seconds +93 weeks, 1 day, 8 hours, 31 minutes, 3 seconds +0 seconds +-1 minute, 36 seconds +900 milliseconds +1 second, 200 milliseconds +1 minute, 1 second +1 week +1 hour + +-- !nullable_no_null -- +1 minute, 36 seconds +1 hour, 2 minutes, 42 seconds +93 weeks, 1 day, 8 hours, 31 minutes, 3 seconds +0 seconds +-1 minute, 36 seconds +900 milliseconds +1 second, 200 milliseconds +1 minute, 1 second +1 week +1 hour + +-- !const_nullable -- +\N +\N +\N +\N +\N +\N +\N +\N +\N +\N + +-- !const_not_nullable -- +1 hour, 2 minutes, 42 seconds +1 hour, 2 minutes, 42 seconds +1 hour, 2 minutes, 42 seconds +1 hour, 2 minutes, 42 seconds +1 hour, 2 minutes, 42 seconds +1 hour, 2 minutes, 42 seconds +1 hour, 2 minutes, 42 seconds +1 hour, 2 minutes, 42 seconds +1 hour, 2 minutes, 42 seconds +1 hour, 2 minutes, 42 seconds + +-- !const_nullable_no_null -- +1 hour, 2 minutes, 42 seconds + diff --git a/regression-test/suites/external_table_p0/dialect_compatible/sql/presto/scalar/timestamp/TestHumanReadableSeconds.sql b/regression-test/suites/external_table_p0/dialect_compatible/sql/presto/scalar/timestamp/TestHumanReadableSeconds.sql index 04dae5ee4e027f..7dbedcd2c84c16 100644 --- a/regression-test/suites/external_table_p0/dialect_compatible/sql/presto/scalar/timestamp/TestHumanReadableSeconds.sql +++ b/regression-test/suites/external_table_p0/dialect_compatible/sql/presto/scalar/timestamp/TestHumanReadableSeconds.sql @@ -1,8 +1,8 @@ set sql_dialect='presto'; set enable_fallback_to_original_planner=false; set debug_skip_fold_constant=false; --- SELECT human_readable_seconds(535333.9513888889); # error: errCode = 2, detailMessage = Can not found function 'human_readable_seconds' --- SELECT human_readable_seconds(535333.2513888889); # error: errCode = 2, detailMessage = Can not found function 'human_readable_seconds' +SELECT human_readable_seconds(535333.9513888889); +SELECT human_readable_seconds(535333.2513888889); set debug_skip_fold_constant=true; --- SELECT human_readable_seconds(535333.9513888889); # error: errCode = 2, detailMessage = Can not found function 'human_readable_seconds' --- SELECT human_readable_seconds(535333.2513888889) # error: errCode = 2, detailMessage = Can not found function 'human_readable_seconds' +SELECT human_readable_seconds(535333.9513888889); +SELECT human_readable_seconds(535333.2513888889); diff --git a/regression-test/suites/query_p0/sql_functions/datetime_functions/test_human_readable_seconds.groovy b/regression-test/suites/query_p0/sql_functions/datetime_functions/test_human_readable_seconds.groovy new file mode 100644 index 00000000000000..55479cfdea9d28 --- /dev/null +++ b/regression-test/suites/query_p0/sql_functions/datetime_functions/test_human_readable_seconds.groovy @@ -0,0 +1,60 @@ +// 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. + +suite("test_human_readable_seconds") { + sql "drop table if exists test_human_readable_seconds" + sql """ + create table test_human_readable_seconds ( + k0 int, + a double not null, + b double null + ) + distributed by hash(k0) + properties + ( + "replication_num" = "1" + ); + """ + + qt_empty_nullable "select human_readable_seconds(b) from test_human_readable_seconds order by k0" + qt_empty_not_nullable "select human_readable_seconds(a) from test_human_readable_seconds order by k0" + + sql "insert into test_human_readable_seconds values (1, 1, null), (2, 1, null), (3, 1, null)" + qt_all_null "select human_readable_seconds(b) from test_human_readable_seconds order by k0" + + sql "truncate table test_human_readable_seconds" + sql """ + insert into test_human_readable_seconds values + (1, 96, 96), + (2, 3762, 3762), + (3, 56363463, 56363463), + (4, 0, 0), + (5, -96, -96), + (6, 0.9, 0.9), + (7, 1.2, 1.2), + (8, 61, 61), + (9, 604800, 604800), + (10, 3600, null); + """ + + qt_nullable "select human_readable_seconds(b) from test_human_readable_seconds order by k0" + qt_not_nullable "select human_readable_seconds(a) from test_human_readable_seconds order by k0" + qt_nullable_no_null "select human_readable_seconds(nullable(a)) from test_human_readable_seconds order by k0" + qt_const_nullable "select human_readable_seconds(NULL) from test_human_readable_seconds order by k0" + qt_const_not_nullable "select human_readable_seconds(3762) from test_human_readable_seconds order by k0" + qt_const_nullable_no_null "select human_readable_seconds(nullable(3762))" +}