From 0891087d795495b69b99485b7c0f6f562687a8f5 Mon Sep 17 00:00:00 2001 From: xufei Date: Wed, 20 Sep 2023 16:55:42 +0800 Subject: [PATCH] This is an automated cherry-pick of #8114 Signed-off-by: ti-chi-bot --- dbms/src/Functions/FunctionsMath.h | 35 ++- .../Functions/tests/gtest_functions_log.cpp | 208 ++++++++++++++++++ .../expr/{issue3373.test => issue_3373.test} | 0 tests/fullstack-test/expr/issue_8113.test | 22 ++ 4 files changed, 262 insertions(+), 3 deletions(-) create mode 100644 dbms/src/Functions/tests/gtest_functions_log.cpp rename tests/fullstack-test/expr/{issue3373.test => issue_3373.test} (100%) create mode 100644 tests/fullstack-test/expr/issue_8113.test diff --git a/dbms/src/Functions/FunctionsMath.h b/dbms/src/Functions/FunctionsMath.h index 9cd137672da..8cd680dd237 100644 --- a/dbms/src/Functions/FunctionsMath.h +++ b/dbms/src/Functions/FunctionsMath.h @@ -581,9 +581,33 @@ struct PiImpl }; +bool logNullable(double b, double & result) +{ + if (b <= 0) + return true; + result = log(b); + return false; +} + +bool log2Nullable(double b, double & result) +{ + if (b <= 0) + return true; + result = log2(b); + return false; +} + +bool log10Nullable(double b, double & result) +{ + if (b <= 0) + return true; + result = log10(b); + return false; +} + bool log2args(double b, double e, double & result) { - if (b == 1 || b < 0 || e < 0) + if (b == 1 || b <= 0 || e <= 0) { return true; } @@ -696,13 +720,18 @@ using FunctionSign = FunctionMathUnaryFloat64; using FunctionPi = FunctionMathNullaryConstFloat64; using FunctionExp = FunctionMathUnaryFloat64>; -using FunctionLog = FunctionMathUnaryFloat64>; +using FunctionLog = FunctionMathUnaryFloat64Nullable>; using FunctionLog2Args = FunctionMathBinaryFloat64Nullable>; using FunctionExp2 = FunctionMathUnaryFloat64>; -using FunctionLog2 = FunctionMathUnaryFloat64>; +using FunctionLog2 = FunctionMathUnaryFloat64Nullable>; using FunctionExp10 = FunctionMathUnaryFloat64>; +<<<<<<< HEAD using FunctionLog10 = FunctionMathUnaryFloat64>; using FunctionSqrt = FunctionMathUnaryFloat64>; +======= +using FunctionLog10 = FunctionMathUnaryFloat64Nullable>; +using FunctionSqrt = FunctionMathUnaryFloat64Nullable>; +>>>>>>> d8fa1d1c3d (Fix func log error (#8114)) using FunctionCbrt = FunctionMathUnaryFloat64 +#include +#include +#include +#include +#include +#include +#include +#include + +namespace DB +{ +namespace tests +{ +class TestFunctionLog : public DB::tests::FunctionTest +{ +}; + +TEST_F(TestFunctionLog, Log) +try +{ + String func_name = "log"; + /// not null column + auto input = createColumn({-1, 0, 0.5, 1, 2}); + auto ref = std::log(0.5); + auto output = createColumn>({{}, {}, ref, 0, -ref}); + ASSERT_COLUMN_EQ(output, executeFunction(func_name, input)); + /// nullable column + input = createColumn>({{}, -1, 0, 0.5, 1, 2}); + output = createColumn>({{}, {}, {}, ref, 0, -ref}); + ASSERT_COLUMN_EQ(output, executeFunction(func_name, input)); + /// not null constant + input = createConstColumn(5, 0); + output = createConstColumn>(5, {}); + ASSERT_COLUMN_EQ(output, executeFunction(func_name, input)); + input = createConstColumn(5, 1); + output = createConstColumn>(5, 0); + ASSERT_COLUMN_EQ(output, executeFunction(func_name, input)); + /// nullable constant with not null value + input = createConstColumn>(5, 0); + output = createConstColumn>(5, {}); + ASSERT_COLUMN_EQ(output, executeFunction(func_name, input)); + input = createConstColumn>(5, 1); + output = createConstColumn>(5, 0); + ASSERT_COLUMN_EQ(output, executeFunction(func_name, input)); + /// nullable constant with null value + input = createConstColumn>(5, {}); + output = createConstColumn>(5, {}); + ASSERT_COLUMN_EQ(output, executeFunction(func_name, input)); + /// typeNothing + input = createOnlyNullColumnConst(5); + output = createOnlyNullColumnConst(5); + ASSERT_COLUMN_EQ(output, executeFunction(func_name, input)); + /// don't need to test other data tpe like int/decimal since TiDB will ensure the input must be float64 +} +CATCH + +TEST_F(TestFunctionLog, Log2Args) +try +{ + String func_name = "log2args"; + /// func(column,column) + auto input1 = createColumn({1, 0, -1, 2, 2, 2}); + auto input2 = createColumn({2, 2, 2, 0, -1, 2}); + auto output = createColumn>({{}, {}, {}, {}, {}, 1}); + ASSERT_COLUMN_EQ(output, executeFunction(func_name, input1, input2)); + input1 = createColumn>({1, 0, -1, 2, 2, 2, {}}); + input2 = createColumn({2, 2, 2, 0, -1, 2, 2}); + output = createColumn>({{}, {}, {}, {}, {}, 1, {}}); + ASSERT_COLUMN_EQ(output, executeFunction(func_name, input1, input2)); + input1 = createColumn({1, 0, -1, 2, 2, 2, 2}); + input2 = createColumn>({2, 2, 2, 0, -1, 2, {}}); + output = createColumn>({{}, {}, {}, {}, {}, 1, {}}); + ASSERT_COLUMN_EQ(output, executeFunction(func_name, input1, input2)); + input1 = createColumn>({1, 0, -1, 2, 2, 2, 2}); + input2 = createColumn>({2, 2, 2, 0, -1, 2, {}}); + output = createColumn>({{}, {}, {}, {}, {}, 1, {}}); + ASSERT_COLUMN_EQ(output, executeFunction(func_name, input1, input2)); + /// func(const,column) + input1 = createConstColumn(7, 2); + input2 = createColumn({2, 2, 2, 0, -1, 2, 2}); + output = createColumn>({1, 1, 1, {}, {}, 1, 1}); + ASSERT_COLUMN_EQ(output, executeFunction(func_name, input1, input2)); + /// func(column,const) + input1 = createColumn>({1, 0, -1, 2, 2, 2, {}}); + input2 = createConstColumn(7, 2); + output = createColumn>({{}, {}, {}, 1, 1, 1, {}}); + ASSERT_COLUMN_EQ(output, executeFunction(func_name, input1, input2)); + /// func(const,const) + input1 = createConstColumn(7, 2); + input2 = createConstColumn(7, 2); + output = createConstColumn>(7, 1); + ASSERT_COLUMN_EQ(output, executeFunction(func_name, input1, input2)); + input1 = createConstColumn(7, 1); + input2 = createConstColumn(7, 2); + output = createConstColumn>(7, {}); + ASSERT_COLUMN_EQ(output, executeFunction(func_name, input1, input2)); + /// typeNothing + input1 = createOnlyNullColumnConst(5); + input2 = createConstColumn(5, 2); + output = createOnlyNullColumnConst(5); + ASSERT_COLUMN_EQ(output, executeFunction(func_name, input1, input2)); + input1 = createConstColumn(5, 2); + input2 = createOnlyNullColumnConst(5); + output = createOnlyNullColumnConst(5); + ASSERT_COLUMN_EQ(output, executeFunction(func_name, input1, input2)); + input1 = createOnlyNullColumnConst(5); + input2 = createOnlyNullColumnConst(5); + output = createOnlyNullColumnConst(5); + ASSERT_COLUMN_EQ(output, executeFunction(func_name, input1, input2)); +} +CATCH + +TEST_F(TestFunctionLog, Log2) +try +{ + String func_name = "log2"; + /// not null column + auto input = createColumn({-1, 0, 0.5, 1, 2}); + auto ref = std::log2(0.5); + auto output = createColumn>({{}, {}, ref, 0, -ref}); + ASSERT_COLUMN_EQ(output, executeFunction(func_name, input)); + /// nullable column + input = createColumn>({{}, -1, 0, 0.5, 1, 2}); + output = createColumn>({{}, {}, {}, ref, 0, -ref}); + ASSERT_COLUMN_EQ(output, executeFunction(func_name, input)); + /// not null constant + input = createConstColumn(5, 0); + output = createConstColumn>(5, {}); + ASSERT_COLUMN_EQ(output, executeFunction(func_name, input)); + input = createConstColumn(5, 1); + output = createConstColumn>(5, 0); + ASSERT_COLUMN_EQ(output, executeFunction(func_name, input)); + /// nullable constant with not null value + input = createConstColumn>(5, 0); + output = createConstColumn>(5, {}); + ASSERT_COLUMN_EQ(output, executeFunction(func_name, input)); + input = createConstColumn>(5, 1); + output = createConstColumn>(5, 0); + ASSERT_COLUMN_EQ(output, executeFunction(func_name, input)); + /// nullable constant with null value + input = createConstColumn>(5, {}); + output = createConstColumn>(5, {}); + ASSERT_COLUMN_EQ(output, executeFunction(func_name, input)); + /// typeNothing + input = createOnlyNullColumnConst(5); + output = createOnlyNullColumnConst(5); + ASSERT_COLUMN_EQ(output, executeFunction(func_name, input)); + /// don't need to test other data tpe like int/decimal since TiDB will ensure the input must be float64 +} +CATCH + +TEST_F(TestFunctionLog, Log10) +try +{ + String func_name = "log10"; + /// not null column + auto input = createColumn({-1, 0, 0.5, 1, 2}); + auto ref = std::log10(0.5); + auto output = createColumn>({{}, {}, ref, 0, -ref}); + ASSERT_COLUMN_EQ(output, executeFunction(func_name, input)); + /// nullable column + input = createColumn>({{}, -1, 0, 0.5, 1, 2}); + output = createColumn>({{}, {}, {}, ref, 0, -ref}); + ASSERT_COLUMN_EQ(output, executeFunction(func_name, input)); + /// not null constant + input = createConstColumn(5, 0); + output = createConstColumn>(5, {}); + ASSERT_COLUMN_EQ(output, executeFunction(func_name, input)); + input = createConstColumn(5, 1); + output = createConstColumn>(5, 0); + ASSERT_COLUMN_EQ(output, executeFunction(func_name, input)); + /// nullable constant with not null value + input = createConstColumn>(5, 0); + output = createConstColumn>(5, {}); + ASSERT_COLUMN_EQ(output, executeFunction(func_name, input)); + input = createConstColumn>(5, 1); + output = createConstColumn>(5, 0); + ASSERT_COLUMN_EQ(output, executeFunction(func_name, input)); + /// nullable constant with null value + input = createConstColumn>(5, {}); + output = createConstColumn>(5, {}); + ASSERT_COLUMN_EQ(output, executeFunction(func_name, input)); + /// typeNothing + input = createOnlyNullColumnConst(5); + output = createOnlyNullColumnConst(5); + ASSERT_COLUMN_EQ(output, executeFunction(func_name, input)); + /// don't need to test other data tpe like int/decimal since TiDB will ensure the input must be float64 +} +CATCH + +} // namespace tests + +} // namespace DB diff --git a/tests/fullstack-test/expr/issue3373.test b/tests/fullstack-test/expr/issue_3373.test similarity index 100% rename from tests/fullstack-test/expr/issue3373.test rename to tests/fullstack-test/expr/issue_3373.test diff --git a/tests/fullstack-test/expr/issue_8113.test b/tests/fullstack-test/expr/issue_8113.test new file mode 100644 index 00000000000..ace869ec0e7 --- /dev/null +++ b/tests/fullstack-test/expr/issue_8113.test @@ -0,0 +1,22 @@ +# Copyright 2023 PingCAP, Inc. +# +# Licensed 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. + +mysql> drop table if exists test.t0 +mysql> create table test.t0(c0 BOOL); +mysql> INSERT INTO test.t0 VALUES (false) +mysql> alter table test.t0 set tiflash replica 1 + +func> wait_table test t0 + +mysql> use test; set tidb_enforce_mpp=1; SELECT /*+ READ_FROM_STORAGE(TIFLASH[t0])*/t0.c0 FROM t0 WHERE LOG(t0.c0)