This is an automated email from the ASF dual-hosted git repository. zhangstar333 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 dffbd5108db [Enhancement] Support some math functions (#48476) dffbd5108db is described below commit dffbd5108db7ab022f01a8a619091857e442005c Author: Nya~ <chenmiao...@gmail.com> AuthorDate: Tue Mar 25 17:34:51 2025 +0800 [Enhancement] Support some math functions (#48476) ### What problem does this PR solve? Related PR: #48203 Problem Summary: support simple sql function for sinh(from Trino), asinh, atanh, acosh --- be/src/vec/functions/math.cpp | 28 +++++++++ be/test/vec/function/function_math_test.cpp | 60 ++++++++++++++++++ fe/fe-core/pom.xml | 4 ++ .../doris/catalog/BuiltinScalarFunctions.java | 8 +++ .../functions/executable/NumericArithmetic.java | 50 +++++++++++++++ .../trees/expressions/functions/scalar/Acosh.java | 68 +++++++++++++++++++++ .../trees/expressions/functions/scalar/Asinh.java | 67 ++++++++++++++++++++ .../trees/expressions/functions/scalar/Atanh.java | 68 +++++++++++++++++++++ .../trees/expressions/functions/scalar/Sinh.java | 68 +++++++++++++++++++++ .../expressions/visitor/ScalarFunctionVisitor.java | 20 ++++++ fe/pom.xml | 7 +++ .../test_math_unary_always_nullable.out | Bin 1032 -> 1769 bytes .../fold_constant_numeric_arithmatic.groovy | 48 ++++++++++++++- .../test_math_unary_always_nullable.groovy | 30 ++++++++- 14 files changed, 524 insertions(+), 2 deletions(-) diff --git a/be/src/vec/functions/math.cpp b/be/src/vec/functions/math.cpp index 6e8222bae4b..c4d5f8ed6aa 100644 --- a/be/src/vec/functions/math.cpp +++ b/be/src/vec/functions/math.cpp @@ -60,6 +60,13 @@ struct AcosName { using FunctionAcos = FunctionMathUnaryAlwayNullable<UnaryFunctionPlainAlwayNullable<AcosName, std::acos>>; +struct AcoshName { + static constexpr auto name = "acosh"; + static constexpr bool is_invalid_input(Float64 x) { return x < 1; } +}; +using FunctionAcosh = + FunctionMathUnaryAlwayNullable<UnaryFunctionPlainAlwayNullable<AcoshName, std::acosh>>; + struct AsinName { static constexpr auto name = "asin"; // https://dev.mysql.com/doc/refman/8.4/en/mathematical-functions.html#function_asin @@ -68,11 +75,23 @@ struct AsinName { using FunctionAsin = FunctionMathUnaryAlwayNullable<UnaryFunctionPlainAlwayNullable<AsinName, std::asin>>; +struct AsinhName { + static constexpr auto name = "asinh"; +}; +using FunctionAsinh = FunctionMathUnary<UnaryFunctionPlain<AsinhName, std::asinh>>; + struct AtanName { static constexpr auto name = "atan"; }; using FunctionAtan = FunctionMathUnary<UnaryFunctionPlain<AtanName, std::atan>>; +struct AtanhName { + static constexpr auto name = "atanh"; + static constexpr bool is_invalid_input(Float64 x) { return x <= -1 || x >= 1; } +}; +using FunctionAtanh = + FunctionMathUnaryAlwayNullable<UnaryFunctionPlainAlwayNullable<AtanhName, std::atanh>>; + template <typename A, typename B> struct Atan2Impl { using ResultType = double; @@ -247,6 +266,11 @@ struct UnaryFunctionPlainSin { using FunctionSin = FunctionMathUnary<UnaryFunctionPlainSin>; +struct SinhName { + static constexpr auto name = "sinh"; +}; +using FunctionSinh = FunctionMathUnary<UnaryFunctionPlain<SinhName, std::sinh>>; + struct SqrtName { static constexpr auto name = "sqrt"; // https://dev.mysql.com/doc/refman/8.4/en/mathematical-functions.html#function_sqrt @@ -427,8 +451,11 @@ public: // so mush. Split it to speed up compile time in the future void register_function_math(SimpleFunctionFactory& factory) { factory.register_function<FunctionAcos>(); + factory.register_function<FunctionAcosh>(); factory.register_function<FunctionAsin>(); + factory.register_function<FunctionAsinh>(); factory.register_function<FunctionAtan>(); + factory.register_function<FunctionAtanh>(); factory.register_function<FunctionAtan2>(); factory.register_function<FunctionCos>(); factory.register_function<FunctionCosh>(); @@ -445,6 +472,7 @@ void register_function_math(SimpleFunctionFactory& factory) { factory.register_function<FunctionNegative>(); factory.register_function<FunctionPositive>(); factory.register_function<FunctionSin>(); + factory.register_function<FunctionSinh>(); factory.register_function<FunctionSqrt>(); factory.register_alias("sqrt", "dsqrt"); factory.register_function<FunctionCbrt>(); diff --git a/be/test/vec/function/function_math_test.cpp b/be/test/vec/function/function_math_test.cpp index bb24d141e4c..a0feec51753 100644 --- a/be/test/vec/function/function_math_test.cpp +++ b/be/test/vec/function/function_math_test.cpp @@ -43,6 +43,21 @@ TEST(MathFunctionTest, acos_test) { static_cast<void>(check_function<DataTypeFloat64, true>(func_name, input_types, data_set)); } +TEST(MathFunctionTest, acosh_test) { + std::string func_name = "acosh"; // acosh(x) = ln(x + sqrt(x^2 - 1)), x ∈ [1, +∞) + + std::vector input_types = {TypeIndex::Float64}; + + DataSet data_set = {{{1.0}, 0.0}, + {{2.0}, 1.3169578969248168}, + {{3.0}, 1.7627471740390861}, + {{10.0}, 2.9932228461263808}, + {{100.0}, 5.2982923656104850}}; + + static_cast<void>( + check_function_all_arg_comb<DataTypeFloat64, true>(func_name, input_types, data_set)); +} + TEST(MathFunctionTest, asin_test) { std::string func_name = "asin"; //[-1,1] -->[-pi_2, pi_2] @@ -54,6 +69,21 @@ TEST(MathFunctionTest, asin_test) { static_cast<void>(check_function<DataTypeFloat64, true>(func_name, input_types, data_set)); } +TEST(MathFunctionTest, asinh_test) { + std::string func_name = "asinh"; // asinh(x) = ln(x + sqrt(x^2 + 1)), x ∈ (-∞, +∞) + + std::vector input_types = {TypeIndex::Float64}; + + DataSet data_set = {{{0.0}, 0.0}, + {{1.0}, 0.8813735870195430}, + {{-1.0}, -0.8813735870195430}, + {{2.0}, 1.4436354751788103}, + {{-2.0}, -1.4436354751788103}}; + + static_cast<void>( + check_function_all_arg_comb<DataTypeFloat64, true>(func_name, input_types, data_set)); +} + TEST(MathFunctionTest, atan_test) { std::string func_name = "atan"; //[-,+] -->(pi_2,pi_2) @@ -67,6 +97,21 @@ TEST(MathFunctionTest, atan_test) { static_cast<void>(check_function<DataTypeFloat64, true>(func_name, input_types, data_set)); } +TEST(MathFunctionTest, atanh_test) { + std::string func_name = "atanh"; // atanh(x) = 0.5 * ln((1 + x) / (1 - x)), x ∈ (-1, 1) + + std::vector input_types = {TypeIndex::Float64}; + + DataSet data_set = {{{0.0}, 0.0}, + {{0.5}, 0.5493061443340549}, + {{-0.5}, -0.5493061443340549}, + {{0.9}, 1.4722194895832204}, + {{-0.9}, -1.4722194895832204}}; + + static_cast<void>( + check_function_all_arg_comb<DataTypeFloat64, true>(func_name, input_types, data_set)); +} + TEST(MathFunctionTest, cos_test) { std::string func_name = "cos"; @@ -95,6 +140,21 @@ TEST(MathFunctionTest, sin_test) { static_cast<void>(check_function<DataTypeFloat64, true>(func_name, input_types, data_set)); } +TEST(MathFunctionTest, sinh_test) { + std::string func_name = "sinh"; // sinh(x) = (e^x - e^(-x)) / 2, x ∈ (-∞, +∞) + + std::vector input_types = {TypeIndex::Float64}; + + DataSet data_set = {{{0.0}, 0.0}, + {{1.0}, 1.1752011936438014}, + {{-1.0}, -1.1752011936438014}, + {{2.0}, 3.6268604078470186}, + {{-2.0}, -3.6268604078470186}}; + + static_cast<void>( + check_function_all_arg_comb<DataTypeFloat64, true>(func_name, input_types, data_set)); +} + TEST(MathFunctionTest, sqrt_test) { std::string func_name = "sqrt"; //sqrt(x) x>=0 diff --git a/fe/fe-core/pom.xml b/fe/fe-core/pom.xml index 52bb3ef7329..f7048b9f03d 100644 --- a/fe/fe-core/pom.xml +++ b/fe/fe-core/pom.xml @@ -131,6 +131,10 @@ under the License. <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> </dependency> + <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-math3</artifactId> + </dependency> <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-pool2 --> <dependency> <groupId>org.apache.commons</groupId> 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 e6ce3de8c6f..ebf9f786ccf 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 @@ -21,6 +21,7 @@ import org.apache.doris.nereids.trees.expressions.Like; import org.apache.doris.nereids.trees.expressions.Regexp; import org.apache.doris.nereids.trees.expressions.functions.scalar.Abs; import org.apache.doris.nereids.trees.expressions.functions.scalar.Acos; +import org.apache.doris.nereids.trees.expressions.functions.scalar.Acosh; import org.apache.doris.nereids.trees.expressions.functions.scalar.AesDecrypt; import org.apache.doris.nereids.trees.expressions.functions.scalar.AesEncrypt; import org.apache.doris.nereids.trees.expressions.functions.scalar.AppendTrailingCharIfAbsent; @@ -75,9 +76,11 @@ import org.apache.doris.nereids.trees.expressions.functions.scalar.ArrayZip; import org.apache.doris.nereids.trees.expressions.functions.scalar.ArraysOverlap; import org.apache.doris.nereids.trees.expressions.functions.scalar.Ascii; import org.apache.doris.nereids.trees.expressions.functions.scalar.Asin; +import org.apache.doris.nereids.trees.expressions.functions.scalar.Asinh; import org.apache.doris.nereids.trees.expressions.functions.scalar.AssertTrue; import org.apache.doris.nereids.trees.expressions.functions.scalar.Atan; import org.apache.doris.nereids.trees.expressions.functions.scalar.Atan2; +import org.apache.doris.nereids.trees.expressions.functions.scalar.Atanh; import org.apache.doris.nereids.trees.expressions.functions.scalar.AutoPartitionName; import org.apache.doris.nereids.trees.expressions.functions.scalar.Bin; import org.apache.doris.nereids.trees.expressions.functions.scalar.BitCount; @@ -381,6 +384,7 @@ import org.apache.doris.nereids.trees.expressions.functions.scalar.Sha1; import org.apache.doris.nereids.trees.expressions.functions.scalar.Sha2; import org.apache.doris.nereids.trees.expressions.functions.scalar.Sign; import org.apache.doris.nereids.trees.expressions.functions.scalar.Sin; +import org.apache.doris.nereids.trees.expressions.functions.scalar.Sinh; import org.apache.doris.nereids.trees.expressions.functions.scalar.Sleep; import org.apache.doris.nereids.trees.expressions.functions.scalar.Sm3; import org.apache.doris.nereids.trees.expressions.functions.scalar.Sm3sum; @@ -496,6 +500,7 @@ public class BuiltinScalarFunctions implements FunctionHelper { public final List<ScalarFunc> scalarFunctions = ImmutableList.of( scalar(Abs.class, "abs"), scalar(Acos.class, "acos"), + scalar(Acosh.class, "acosh"), scalar(AesDecrypt.class, "aes_decrypt"), scalar(AesEncrypt.class, "aes_encrypt"), scalar(AppendTrailingCharIfAbsent.class, "append_trailing_char_if_absent"), @@ -550,8 +555,10 @@ public class BuiltinScalarFunctions implements FunctionHelper { scalar(ArraysOverlap.class, "arrays_overlap"), scalar(Ascii.class, "ascii"), scalar(Asin.class, "asin"), + scalar(Asinh.class, "asinh"), scalar(AssertTrue.class, "assert_true"), scalar(Atan.class, "atan"), + scalar(Atanh.class, "atanh"), scalar(Atan2.class, "atan2"), scalar(AutoPartitionName.class, "auto_partition_name"), scalar(Bin.class, "bin"), @@ -874,6 +881,7 @@ public class BuiltinScalarFunctions implements FunctionHelper { scalar(Sha2.class, "sha2"), scalar(Sign.class, "sign"), scalar(Sin.class, "sin"), + scalar(Sinh.class, "sinh"), scalar(Sleep.class, "sleep"), scalar(StructElement.class, "struct_element"), scalar(Sm3.class, "sm3"), diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/executable/NumericArithmetic.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/executable/NumericArithmetic.java index 57eda59ee7d..4859a61f950 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/executable/NumericArithmetic.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/executable/NumericArithmetic.java @@ -36,6 +36,8 @@ import org.apache.doris.nereids.trees.expressions.literal.VarcharLiteral; import org.apache.doris.nereids.types.DecimalV3Type; import org.apache.doris.nereids.types.DoubleType; +import org.apache.commons.math3.util.FastMath; + import java.math.BigDecimal; import java.math.BigInteger; import java.nio.charset.StandardCharsets; @@ -893,6 +895,17 @@ public class NumericArithmetic { return checkOutputBoundary(new DoubleLiteral(Math.sin(first.getValue()))); } + /** + * sinh + */ + @ExecFunction(name = "sinh") + public static Expression sinh(DoubleLiteral first) { + if (inputOutOfBound(first, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, false, false)) { + return new NullLiteral(DoubleType.INSTANCE); + } + return checkOutputBoundary(new DoubleLiteral(Math.sinh(first.getValue()))); + } + /** * cos */ @@ -942,9 +955,46 @@ public class NumericArithmetic { */ @ExecFunction(name = "atan") public static Expression atan(DoubleLiteral first) { + if (inputOutOfBound(first, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, false, false)) { + return new NullLiteral(DoubleType.INSTANCE); + } return checkOutputBoundary(new DoubleLiteral(Math.atan(first.getValue()))); } + /** + * asinh + */ + @ExecFunction(name = "asinh") + public static Expression asinh(DoubleLiteral first) { + if (inputOutOfBound(first, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, false, false)) { + return new NullLiteral(DoubleType.INSTANCE); + } + return checkOutputBoundary(new DoubleLiteral(FastMath.asinh(first.getValue()))); + } + + /** + * acosh + */ + @ExecFunction(name = "acosh") + public static Expression acosh(DoubleLiteral first) { + if (inputOutOfBound(first, Double.NEGATIVE_INFINITY, 1.0, false, false)) { + return new NullLiteral(DoubleType.INSTANCE); + } + return checkOutputBoundary(new DoubleLiteral(FastMath.acosh(first.getValue()))); + } + + /** + * atanh + */ + @ExecFunction(name = "atanh") + public static Expression atanh(DoubleLiteral first) { + if (inputOutOfBound(first, 1.0, Double.POSITIVE_INFINITY, true, false) + || inputOutOfBound(first, Double.NEGATIVE_INFINITY, -1.0, false, true)) { + return new NullLiteral(DoubleType.INSTANCE); + } + return checkOutputBoundary(new DoubleLiteral(FastMath.atanh(first.getValue()))); + } + /** * atan2 */ diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Acosh.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Acosh.java new file mode 100644 index 00000000000..d7c80589524 --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Acosh.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.AlwaysNullable; +import org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSignature; +import org.apache.doris.nereids.trees.expressions.functions.PropagateNullLiteral; +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 com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; + +import java.util.List; + +/** + * ScalarFunction Acosh + */ +public class Acosh extends ScalarFunction + implements UnaryExpression, ExplicitlyCastableSignature, AlwaysNullable, PropagateNullLiteral { + public static final List<FunctionSignature> SIGNATURES = ImmutableList.of( + FunctionSignature.ret(DoubleType.INSTANCE).args(DoubleType.INSTANCE) + ); + + /** + * constructor with 1 argument. + */ + public Acosh(Expression arg) { + super("acosh", arg); + } + + /** + * withChildren. + */ + @Override + public Acosh withChildren(List<Expression> children) { + Preconditions.checkArgument(children.size() == 1); + return new Acosh(children.get(0)); + } + + @Override + public List<FunctionSignature> getSignatures() { + return SIGNATURES; + } + + @Override + public <R, C> R accept(ExpressionVisitor<R, C> visitor, C context) { + return visitor.visitAcosh(this, context); + } +} diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Asinh.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Asinh.java new file mode 100644 index 00000000000..d51b2de1ae1 --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Asinh.java @@ -0,0 +1,67 @@ +// 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 com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; + +import java.util.List; + +/** + * ScalarFunction asinh + */ +public class Asinh extends ScalarFunction + implements UnaryExpression, ExplicitlyCastableSignature, PropagateNullable { + public static final List<FunctionSignature> SIGNATURES = ImmutableList.of( + FunctionSignature.ret(DoubleType.INSTANCE).args(DoubleType.INSTANCE) + ); + + /** + * constructor with 1 argument. + */ + public Asinh(Expression arg) { + super("asinh", arg); + } + + /** + * withChildren. + */ + @Override + public Asinh withChildren(List<Expression> children) { + Preconditions.checkArgument(children.size() == 1); + return new Asinh(children.get(0)); + } + + @Override + public List<FunctionSignature> getSignatures() { + return SIGNATURES; + } + + @Override + public <R, C> R accept(ExpressionVisitor<R, C> visitor, C context) { + return visitor.visitAsinh(this, context); + } +} diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Atanh.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Atanh.java new file mode 100644 index 00000000000..4f0931caf12 --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Atanh.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.AlwaysNullable; +import org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSignature; +import org.apache.doris.nereids.trees.expressions.functions.PropagateNullLiteral; +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 com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; + +import java.util.List; + +/** + * ScalarFunction atanh + */ +public class Atanh extends ScalarFunction + implements UnaryExpression, ExplicitlyCastableSignature, AlwaysNullable, PropagateNullLiteral { + public static final List<FunctionSignature> SIGNATURES = ImmutableList.of( + FunctionSignature.ret(DoubleType.INSTANCE).args(DoubleType.INSTANCE) + ); + + /** + * constructor with 1 argument. + */ + public Atanh(Expression arg) { + super("atanh", arg); + } + + /** + * withChildren. + */ + @Override + public Atanh withChildren(List<Expression> children) { + Preconditions.checkArgument(children.size() == 1); + return new Atanh(children.get(0)); + } + + @Override + public List<FunctionSignature> getSignatures() { + return SIGNATURES; + } + + @Override + public <R, C> R accept(ExpressionVisitor<R, C> visitor, C context) { + return visitor.visitAtanh(this, context); + } +} diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Sinh.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Sinh.java new file mode 100644 index 00000000000..b1cdd188aa1 --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Sinh.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 com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; + +import java.util.List; + +/** + * ScalarFunction Sinh + */ +public class Sinh extends ScalarFunction + implements UnaryExpression, ExplicitlyCastableSignature, PropagateNullable { + + public static final List<FunctionSignature> SIGNATURES = ImmutableList.of( + FunctionSignature.ret(DoubleType.INSTANCE).args(DoubleType.INSTANCE) + ); + + /** + * constructor with 1 argument. + */ + public Sinh(Expression arg) { + super("sinh", arg); + } + + /** + * withChildren. + */ + @Override + public Sinh withChildren(List<Expression> children) { + Preconditions.checkArgument(children.size() == 1); + return new Sinh(children.get(0)); + } + + @Override + public List<FunctionSignature> getSignatures() { + return SIGNATURES; + } + + @Override + public <R, C> R accept(ExpressionVisitor<R, C> visitor, C context) { + return visitor.visitSinh(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 c4589cfe02c..f1737db8e59 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 @@ -23,6 +23,7 @@ import org.apache.doris.nereids.trees.expressions.StringRegexPredicate; import org.apache.doris.nereids.trees.expressions.functions.combinator.StateCombinator; import org.apache.doris.nereids.trees.expressions.functions.scalar.Abs; import org.apache.doris.nereids.trees.expressions.functions.scalar.Acos; +import org.apache.doris.nereids.trees.expressions.functions.scalar.Acosh; import org.apache.doris.nereids.trees.expressions.functions.scalar.AesDecrypt; import org.apache.doris.nereids.trees.expressions.functions.scalar.AesEncrypt; import org.apache.doris.nereids.trees.expressions.functions.scalar.AppendTrailingCharIfAbsent; @@ -82,9 +83,11 @@ import org.apache.doris.nereids.trees.expressions.functions.scalar.ArrayZip; import org.apache.doris.nereids.trees.expressions.functions.scalar.ArraysOverlap; import org.apache.doris.nereids.trees.expressions.functions.scalar.Ascii; import org.apache.doris.nereids.trees.expressions.functions.scalar.Asin; +import org.apache.doris.nereids.trees.expressions.functions.scalar.Asinh; import org.apache.doris.nereids.trees.expressions.functions.scalar.AssertTrue; import org.apache.doris.nereids.trees.expressions.functions.scalar.Atan; import org.apache.doris.nereids.trees.expressions.functions.scalar.Atan2; +import org.apache.doris.nereids.trees.expressions.functions.scalar.Atanh; import org.apache.doris.nereids.trees.expressions.functions.scalar.AutoPartitionName; import org.apache.doris.nereids.trees.expressions.functions.scalar.Bin; import org.apache.doris.nereids.trees.expressions.functions.scalar.BitCount; @@ -379,6 +382,7 @@ import org.apache.doris.nereids.trees.expressions.functions.scalar.Sha1; import org.apache.doris.nereids.trees.expressions.functions.scalar.Sha2; import org.apache.doris.nereids.trees.expressions.functions.scalar.Sign; import org.apache.doris.nereids.trees.expressions.functions.scalar.Sin; +import org.apache.doris.nereids.trees.expressions.functions.scalar.Sinh; import org.apache.doris.nereids.trees.expressions.functions.scalar.Sleep; import org.apache.doris.nereids.trees.expressions.functions.scalar.Sm3; import org.apache.doris.nereids.trees.expressions.functions.scalar.Sm3sum; @@ -494,6 +498,10 @@ public interface ScalarFunctionVisitor<R, C> { return visitScalarFunction(acos, context); } + default R visitAcosh(Acosh acosh, C context) { + return visitScalarFunction(acosh, context); + } + default R visitAesDecrypt(AesDecrypt aesDecrypt, C context) { return visitScalarFunction(aesDecrypt, context); } @@ -730,6 +738,10 @@ public interface ScalarFunctionVisitor<R, C> { return visitScalarFunction(asin, context); } + default R visitAsinh(Asinh asinh, C context) { + return visitScalarFunction(asinh, context); + } + default R visitAssertTrue(AssertTrue assertTrue, C context) { return visitScalarFunction(assertTrue, context); } @@ -738,6 +750,10 @@ public interface ScalarFunctionVisitor<R, C> { return visitScalarFunction(atan, context); } + default R visitAtanh(Atanh atanh, C context) { + return visitScalarFunction(atanh, context); + } + default R visitAtan2(Atan2 atan2, C context) { return visitScalarFunction(atan2, context); } @@ -1891,6 +1907,10 @@ public interface ScalarFunctionVisitor<R, C> { return visitScalarFunction(sin, context); } + default R visitSinh(Sinh sinh, C context) { + return visitScalarFunction(sinh, context); + } + default R visitSleep(Sleep sleep, C context) { return visitScalarFunction(sleep, context); } diff --git a/fe/pom.xml b/fe/pom.xml index 68cfff27e89..55d2763ac52 100644 --- a/fe/pom.xml +++ b/fe/pom.xml @@ -253,6 +253,7 @@ under the License. <commons-pool2.version>2.2</commons-pool2.version> <commons-pool.version>1.5.1</commons-pool.version> <commons-text.version>1.10.0</commons-text.version> + <commons-math3.version>3.6.1</commons-math3.version> <commons-validator.version>1.7</commons-validator.version> <gson.version>2.10.1</gson.version> <guava.version>33.2.1-jre</guava.version> @@ -793,6 +794,12 @@ under the License. <artifactId>commons-lang3</artifactId> <version>${commons-lang3.version}</version> </dependency> + <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-math3 --> + <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-math3</artifactId> + <version>${commons-math3.version}</version> + </dependency> <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-pool2 --> <dependency> <groupId>org.apache.commons</groupId> diff --git a/regression-test/data/query_p0/sql_functions/math_functions/test_math_unary_always_nullable.out b/regression-test/data/query_p0/sql_functions/math_functions/test_math_unary_always_nullable.out index 0a190f0bd6b..ae2203c03d8 100644 Binary files a/regression-test/data/query_p0/sql_functions/math_functions/test_math_unary_always_nullable.out and b/regression-test/data/query_p0/sql_functions/math_functions/test_math_unary_always_nullable.out differ diff --git a/regression-test/suites/nereids_p0/expression/fold_constant/fold_constant_numeric_arithmatic.groovy b/regression-test/suites/nereids_p0/expression/fold_constant/fold_constant_numeric_arithmatic.groovy index bc1cb91ca9d..fcf2d060886 100644 --- a/regression-test/suites/nereids_p0/expression/fold_constant/fold_constant_numeric_arithmatic.groovy +++ b/regression-test/suites/nereids_p0/expression/fold_constant/fold_constant_numeric_arithmatic.groovy @@ -51,6 +51,17 @@ suite("fold_constant_numeric_arithmatic") { testFoldConst("SELECT ACOS(1E308)") testFoldConst("SELECT ACOS(-1E308)") +//Acosh function cases + testFoldConst("SELECT ACOSH(1) AS acosh_case_1"); // acosh(1) = 0 + testFoldConst("SELECT ACOSH(2) AS acosh_case_2"); // acosh(2) ≈ 1.316957897 + testFoldConst("SELECT ACOSH(10) AS acosh_case_3"); // acosh(10) ≈ 2.993222846 + testFoldConst("SELECT ACOSH(0.5)"); // Invalid input (x < 1) + testFoldConst("SELECT ACOSH(-1)"); // Invalid input (x < 1) + testFoldConst("SELECT ACOSH(NULL)"); // NULL handling + testFoldConst("SELECT ACOSH(1E308)"); // Large value + testFoldConst("SELECT ACOSH(-1E308)"); // Invalid input (x < 1) + testFoldConst("SELECT ACOSH(1), ACOSH(2), ACOSH(10)"); // Multiple values + //Asin function cases testFoldConst("SELECT ASIN(1) AS asin_case_1") //asin(1) = π/2 testFoldConst("SELECT ASIN(0) AS asin_case_2") //asin(0) = 0 @@ -65,6 +76,17 @@ suite("fold_constant_numeric_arithmatic") { testFoldConst("SELECT ASIN(1E308)") testFoldConst("SELECT ASIN(-1E308)") +//Asinh function cases + testFoldConst("SELECT ASINH(0) AS asinh_case_1"); // asinh(0) = 0 + testFoldConst("SELECT ASINH(1) AS asinh_case_2"); // asinh(1) ≈ 0.881373587 + testFoldConst("SELECT ASINH(-1) AS asinh_case_3"); // asinh(-1) ≈ -0.881373587 + testFoldConst("SELECT ASINH(0.5)"); // Common value + testFoldConst("SELECT ASINH(-0.5)"); // Negative common value + testFoldConst("SELECT ASINH(NULL)"); // NULL handling + testFoldConst("SELECT ASINH(1E308)"); // Large value + testFoldConst("SELECT ASINH(-1E308)"); // Large negative value + testFoldConst("SELECT ASINH(0), ASINH(1), ASINH(-1)"); // Multiple values + //Atan function cases testFoldConst("SELECT ATAN(1) AS atan_case_1") //atan(1) = π/4 testFoldConst("SELECT ATAN(0) AS atan_case_2") //atan(0) = 0 @@ -77,7 +99,22 @@ suite("fold_constant_numeric_arithmatic") { testFoldConst("SELECT ATAN(PI())") // PI input testFoldConst("SELECT ATAN(-PI())") // Negative PI input testFoldConst("SELECT ATAN(1E-308)") // Very small positive number - testFoldConst("SELECT ATAN(-1E-308)") // Very small negative number + testFoldConst("SELECT ATAN(-1E-308)") // Very small negative + +//Atanh function cases + testFoldConst("SELECT ATANH(0) AS atanh_case_1"); // atanh(0) = 0 + testFoldConst("SELECT ATANH(0.5) AS atanh_case_2"); // atanh(0.5) ≈ 0.549306144 + testFoldConst("SELECT ATANH(-0.5) AS atanh_case_3"); // atanh(-0.5) ≈ -0.549306144 + testFoldConst("SELECT ATANH(0.9)"); // Common value + testFoldConst("SELECT ATANH(-0.9)"); // Negative common value + testFoldConst("SELECT ATANH(NULL)"); // NULL handling + testFoldConst("SELECT ATANH(1)"); // Boundary value (invalid) + testFoldConst("SELECT ATANH(-1)"); // Boundary value (invalid) + testFoldConst("SELECT ATANH(1.5)"); // Invalid input (x > 1) + testFoldConst("SELECT ATANH(-1.5)"); // Invalid input (x < -1) + testFoldConst("SELECT ATANH(1E-308)"); // Very small positive number + testFoldConst("SELECT ATANH(-1E-308)"); // Very small negative number + testFoldConst("SELECT ATANH(0), ATANH(0.5), ATANH(-0.5)"); // Multiple values //Atan2 function cases testFoldConst("SELECT ATAN2(1, 1) AS atan2_case_1") //atan2(1, 1) = π/4 @@ -455,6 +492,15 @@ suite("fold_constant_numeric_arithmatic") { testFoldConst("SELECT SIN(1E308) AS sin_case_overflow") testFoldConst("SELECT sin(0), sin(pi()/2), sin(pi()), sin(3*pi()/2)") +// Sinh function cases + testFoldConst("SELECT SINH(0) AS sinh_case_1"); // sinh(0) = 0 + testFoldConst("SELECT SINH(1) AS sinh_case_2"); // sinh(1) ≈ 1.175201194 + testFoldConst("SELECT SINH(-1) AS sinh_case_3"); // sinh(-1) ≈ -1.175201194 + testFoldConst("SELECT SINH(2) AS sinh_case_4"); // sinh(2) ≈ 3.626860408 + testFoldConst("SELECT SINH(NULL)"); // NULL handling + // testFoldConst("SELECT SINH(1E308) AS sinh_case_overflow"); // Error for input String "inf" + testFoldConst("SELECT SINH(0), SINH(1), SINH(-1), SINH(2)"); // Multi value + //Sqrt function cases testFoldConst("SELECT SQRT(16) AS sqrt_case_1") //sqrt(16) = 4 testFoldConst("SELECT SQRT(0) AS sqrt_case_2") //sqrt(0) = 0 diff --git a/regression-test/suites/query_p0/sql_functions/math_functions/test_math_unary_always_nullable.groovy b/regression-test/suites/query_p0/sql_functions/math_functions/test_math_unary_always_nullable.groovy index 282d4e3c575..64b9ddc01ef 100644 --- a/regression-test/suites/query_p0/sql_functions/math_functions/test_math_unary_always_nullable.groovy +++ b/regression-test/suites/query_p0/sql_functions/math_functions/test_math_unary_always_nullable.groovy @@ -30,6 +30,16 @@ suite("test_math_unary_alway_nullable") { select acos(-1.1), acos(-1.1) is NULL, number from numbers("number"="10") """ + qt_acosh_1 """ + select acosh(-1.1), acosh(-1.1) is null; + """ + qt_acosh_2 """ + select acosh(0.0), acosh(0.0) is null; + """ + qt_acosh_3 """ + select acosh(1.1), acosh(1.1) is NULL, number from numbers("number"="10") + """ + qt_asin_1 """ select asin(1.1), asin(1.1) is null; """ @@ -40,6 +50,16 @@ suite("test_math_unary_alway_nullable") { select asin(-1.1), asin(-1.1) is NULL, number from numbers("number"="10") """ + qt_atanh_1 """ + select atanh(-1.0), atanh(-1.0) is null; + """ + qt_atanh_2 """ + select atanh(1.0), atanh(1.0) is null; + """ + qt_atanh_3 """ + select atanh(0.0), atanh(0.0) is NULL, number from numbers("number"="10") + """ + qt_sqrt_1 """ select sqrt(-1), sqrt(-1) is null; """ @@ -70,10 +90,18 @@ suite("test_math_unary_alway_nullable") { select rowid, acos(val), acos(val) is null from test_math_unary_alway_nullable order by rowid; """ + qt_acosh_tbl_1 """ + select rowid, acosh(val), acosh(val) is null from test_math_unary_alway_nullable order by rowid; + """ + qt_asin_tbl_1 """ select rowid, asin(val), asin(val) is null from test_math_unary_alway_nullable order by rowid; """ + qt_atanh_tbl_1 """ + select rowid, atanh(val), atanh(val) is null from test_math_unary_alway_nullable order by rowid; + """ + qt_sqrt_tbl_1 """ select rowid, sqrt(val), sqrt(val) is null from test_math_unary_alway_nullable order by rowid; """ @@ -82,4 +110,4 @@ suite("test_math_unary_alway_nullable") { select rowid, dsqrt(val), dsqrt(val) is null from test_math_unary_alway_nullable order by rowid; """ -} \ No newline at end of file +} --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org For additional commands, e-mail: commits-h...@doris.apache.org