blob: 78e53a055792266756eda5a99af79710556c4f25 [file]
// 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 <gtest/gtest.h>
#include <memory>
#include <string>
#include <vector>
#include "core/data_type/data_type_decimal.h"
#include "core/data_type/data_type_nullable.h"
#include "exprs/function/simple_function_factory.h"
namespace doris {
// Pins the decimal registration surface of the binary arithmetic functions.
//
// FE casts both children of Add/Subtract/Mod to exactly the return type
// (TypeCoercionUtils#processDecimalV3BinaryArithmetic), so BE registers only
// same-width decimal pairs for them. Multiply is exempt from that cast and
// must keep the full width cross product. If someone re-adds mixed-width
// add/subtract/mod registrations (paying ~2/3 of the template instantiations
// of those TUs for unreachable code) or drops a reachable signature, these
// tests fail.
class BinaryArithmeticRegistrationTest : public testing::Test {
protected:
static FunctionBasePtr lookup(const std::string& name, const DataTypePtr& left,
const DataTypePtr& right, const DataTypePtr& return_type) {
ColumnsWithTypeAndName arguments {{nullptr, left, ""}, {nullptr, right, ""}};
return SimpleFunctionFactory::instance().get_function(name, arguments, return_type);
}
static std::vector<DataTypePtr> v3_widths() {
return {std::make_shared<DataTypeDecimal<TYPE_DECIMAL32>>(),
std::make_shared<DataTypeDecimal<TYPE_DECIMAL64>>(),
std::make_shared<DataTypeDecimal<TYPE_DECIMAL128I>>(),
std::make_shared<DataTypeDecimal<TYPE_DECIMAL256>>()};
}
};
TEST_F(BinaryArithmeticRegistrationTest, same_width_add_subtract_resolvable) {
for (const auto& name : {std::string("add"), std::string("subtract")}) {
for (const auto& type : v3_widths()) {
auto function = lookup(name, type, type, type);
ASSERT_NE(function, nullptr) << name << " " << type->get_name();
EXPECT_EQ(function->get_name(), name) << type->get_name();
}
}
}
TEST_F(BinaryArithmeticRegistrationTest, same_width_mod_resolvable) {
for (const auto& type : v3_widths()) {
// FunctionMod always infers a nullable return type (mod by zero -> NULL).
auto function = lookup("mod", type, type, make_nullable(type));
ASSERT_NE(function, nullptr) << type->get_name();
EXPECT_EQ(function->get_name(), "mod") << type->get_name();
}
}
TEST_F(BinaryArithmeticRegistrationTest, mixed_width_add_subtract_mod_unresolvable) {
auto widths = v3_widths();
for (const auto& left : widths) {
for (const auto& right : widths) {
if (left->get_primitive_type() == right->get_primitive_type()) {
continue;
}
for (const auto& name : {std::string("add"), std::string("subtract")}) {
EXPECT_EQ(lookup(name, left, right, left), nullptr)
<< name << " " << left->get_name() << " x " << right->get_name();
}
EXPECT_EQ(lookup("mod", left, right, make_nullable(left)), nullptr)
<< "mod " << left->get_name() << " x " << right->get_name();
}
}
}
TEST_F(BinaryArithmeticRegistrationTest, multiply_full_cross_product_retained) {
auto widths = v3_widths();
for (const auto& left : widths) {
for (const auto& right : widths) {
auto function = lookup("multiply", left, right, left);
ASSERT_NE(function, nullptr)
<< "multiply " << left->get_name() << " x " << right->get_name();
EXPECT_EQ(function->get_name(), "multiply");
}
}
}
TEST_F(BinaryArithmeticRegistrationTest, decimalv2_still_resolvable) {
auto type = std::make_shared<DataTypeDecimalV2>();
for (const auto& name :
{std::string("add"), std::string("subtract"), std::string("multiply")}) {
auto function = lookup(name, type, type, type);
ASSERT_NE(function, nullptr) << name;
EXPECT_EQ(function->get_name(), name);
}
auto mod_function = lookup("mod", type, type, make_nullable(type));
ASSERT_NE(mod_function, nullptr);
EXPECT_EQ(mod_function->get_name(), "mod");
}
} // namespace doris