blob: e719f2cf0f04915435d676f807757fc8d5f61d8d [file] [log] [blame]
// 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 <cstdlib>
#include <fstream>
#include <string>
#include <type_traits>
#include "cast_test.h"
#include "runtime/define_primitive_type.h"
#include "vec/core/types.h"
#include "vec/data_types/data_type_date_or_datetime_v2.h"
#include "vec/data_types/data_type_decimal.h"
#include "vec/data_types/data_type_number.h"
#include "vec/runtime/time_value.h"
namespace doris::vectorized {
using namespace ut_type;
struct FunctionCastToFloatTest : public FunctionCastTest {
const std::vector<std::string> white_spaces = {" ", "\t", "\r", "\n", "\f", "\v"};
std::string white_spaces_str = " \t\r\n\f\v";
bool compareIgnoreCase(const std::string& str1, const std::string& str2) {
std::string s1 = str1;
std::string s2 = str2;
std::transform(s1.begin(), s1.end(), s1.begin(), ::toupper);
std::transform(s2.begin(), s2.end(), s2.begin(), ::toupper);
return s1 == s2;
}
bool is_inf_or_nan_str(const std::string& str) {
return compareIgnoreCase(str, "inf") || compareIgnoreCase(str, "infinity") ||
compareIgnoreCase(str, "nan");
}
void format_decimal_number_func(DataSet& data_set, std::string v_str, auto v, bool is_negative,
bool with_spaces, bool with_sign, bool leading_zeros) {
if (leading_zeros) {
if (!is_inf_or_nan_str(v_str)) {
v_str = "000" + v_str;
}
}
if (is_negative) {
v_str = "-" + v_str;
} else {
// optional '+'
if (with_sign) {
v_str = "+" + v_str;
}
}
if (with_spaces) {
/*
for (const auto& sp : white_spaces) {
// Single whitespace combinations
data_set.push_back({{sp + v_str}, v});
data_set.push_back({{v_str + sp}, v});
data_set.push_back({{sp + v_str + sp}, v});
// Multiple whitespace combinations
data_set.push_back({{sp + sp + sp + v_str}, v});
data_set.push_back({{v_str + sp + sp + sp}, v});
data_set.push_back({{sp + sp + sp + v_str + sp + sp + sp}, v});
}
*/
data_set.push_back({{white_spaces_str + v_str}, v});
data_set.push_back({{v_str + white_spaces_str}, v});
data_set.push_back({{white_spaces_str + v_str + white_spaces_str}, v});
} else {
data_set.push_back({{v_str}, v});
}
}
template <PrimitiveType FloatPType>
void from_string_test_func() {
using FloatType = typename PrimitiveTypeTraits<FloatPType>::CppType;
InputTypeSet input_types = {PrimitiveType::TYPE_VARCHAR};
std::vector<std::string> test_strs = {
"0",
"1",
"9",
"100000",
"123456",
"999999",
"0.",
"1.",
"9.",
"100000.",
"123456.",
"999999.",
".0",
".1",
".9",
".000001",
".000009",
".100000",
".900000",
".100001",
".900009",
"0.123456",
".999999",
"0.0",
"1.0",
"9.0",
"100000.0",
"999999.0",
"123456.0",
"0.000000",
"0.000001",
"0.000009",
"0.100001",
"0.900009",
"1.000000",
"9.000000",
"1.00001",
"9.00001",
"100000.000000",
"100001.000000",
"999999.000000",
"123456.000000",
"123.456",
"999.999",
"nan",
"NaN",
"NAN",
"inf",
"Inf",
"INF",
"infinity",
"Infinity",
"INFINITY",
};
// DataSet data_set = {
// // Zero and sign variations
// {{std::string("0")}, FloatType(0.0)},
// {{std::string("+0")}, FloatType(0.0)},
// {{std::string("-0")}, FloatType(-0.0)},
// {{std::string("0.0")}, FloatType(0.0)},
// {{std::string("+0.0")}, FloatType(0.0)},
// {{std::string("-0.0")}, FloatType(-0.0)},
// {{std::string(".0")}, FloatType(0.0)},
// {{std::string("+.0")}, FloatType(0.0)},
// {{std::string("-.0")}, FloatType(-0.0)},
// // Normal positive values
// {{std::string("1")}, FloatType(1.0)},
// {{std::string("123")}, FloatType(123.0)},
// {{std::string("1.23")}, FloatType(1.23)},
// {{std::string("123.456")}, FloatType(123.456)},
// {{std::string("1.23456")}, FloatType(1.23456)},
// {{std::string("0.123456")}, FloatType(0.123456)},
// {{std::string(".123456")}, FloatType(0.123456)},
// // positive values with plus sign
// {{std::string("+1")}, FloatType(1.0)},
// {{std::string("+123")}, FloatType(123.0)},
// {{std::string("+1.23")}, FloatType(1.23)},
// {{std::string("+123.456")}, FloatType(123.456)},
// {{std::string("+1.23456")}, FloatType(1.23456)},
// {{std::string("+0.123456")}, FloatType(0.123456)},
// {{std::string("+.123456")}, FloatType(0.123456)},
// // Normal negative values
// {{std::string("-1")}, FloatType(-1.0)},
// {{std::string("-123")}, FloatType(-123.0)},
// {{std::string("-1.23")}, FloatType(-1.23)},
// {{std::string("-123.456")}, FloatType(-123.456)},
// {{std::string("-1.23456")}, FloatType(-1.23456)},
// {{std::string("-0.123456")}, FloatType(-0.123456)},
// {{std::string("-.123456")}, FloatType(-0.123456)},
// // Scientific notation (exponent)
// {{std::string("1e0")}, FloatType(1.0)},
// {{std::string("1e1")}, FloatType(10.0)},
// {{std::string("1e-1")}, FloatType(0.1)},
// {{std::string("1.23e2")}, FloatType(123.0)},
// {{std::string("1.23e-2")}, FloatType(0.0123)},
// {{std::string("1.23E2")}, FloatType(123.0)},
// {{std::string("1.23E-2")}, FloatType(0.0123)},
// {{std::string("-1.23e2")}, FloatType(-123.0)},
// {{std::string("-1.23e-2")}, FloatType(-0.0123)},
// // Infinity values
// {{std::string("inf")}, std::numeric_limits<FloatType>::infinity()},
// {{std::string("INF")}, std::numeric_limits<FloatType>::infinity()},
// {{std::string("Inf")}, std::numeric_limits<FloatType>::infinity()},
// {{std::string("infinity")}, std::numeric_limits<FloatType>::infinity()},
// {{std::string("INFINITY")}, std::numeric_limits<FloatType>::infinity()},
// {{std::string("Infinity")}, std::numeric_limits<FloatType>::infinity()},
// {{std::string("+inf")}, std::numeric_limits<FloatType>::infinity()},
// {{std::string("-inf")}, -std::numeric_limits<FloatType>::infinity()},
// {{std::string("+infinity")}, std::numeric_limits<FloatType>::infinity()},
// {{std::string("-infinity")}, -std::numeric_limits<FloatType>::infinity()},
// // NaN values
// {{std::string("nan")}, std::numeric_limits<FloatType>::quiet_NaN()},
// {{std::string("NAN")}, std::numeric_limits<FloatType>::quiet_NaN()},
// {{std::string("NaN")}, std::numeric_limits<FloatType>::quiet_NaN()},
// {{std::string("+nan")}, std::numeric_limits<FloatType>::quiet_NaN()},
// {{std::string("-nan")}, std::numeric_limits<FloatType>::quiet_NaN()},
// // Edge values - using type-specific limits
// {{fmt::format("{}", std::numeric_limits<FloatType>::max())},
// FloatType(std::numeric_limits<FloatType>::max())},
// {{fmt::format("{}", -std::numeric_limits<FloatType>::max())},
// FloatType(-std::numeric_limits<FloatType>::max())},
// {{fmt::format("{}", std::numeric_limits<FloatType>::min())},
// FloatType(std::numeric_limits<FloatType>::min())},
// {{fmt::format("{}", -std::numeric_limits<FloatType>::min())},
// FloatType(-std::numeric_limits<FloatType>::min())},
// // Very small values
// {{fmt::format("{}", std::numeric_limits<FloatType>::denorm_min())},
// FloatType(std::numeric_limits<FloatType>::denorm_min())},
// {{fmt::format("{}", -std::numeric_limits<FloatType>::denorm_min())},
// FloatType(-std::numeric_limits<FloatType>::denorm_min())},
// {{std::string("1e-1000")}, FloatType(0)},
// {{std::string("-1e-1000")}, FloatType(0)},
// // Whitespace variations
// {{std::string(" 1.23")}, FloatType(1.23)},
// {{std::string("1.23 ")}, FloatType(1.23)},
// {{std::string(" 1.23 ")}, FloatType(1.23)},
// {{std::string("\t1.23")}, FloatType(1.23)},
// {{std::string("1.23\t")}, FloatType(1.23)},
// {{std::string("\n1.23")}, FloatType(1.23)},
// {{std::string("1.23\n")}, FloatType(1.23)},
// {{std::string("\r1.23")}, FloatType(1.23)},
// {{std::string("1.23\r")}, FloatType(1.23)},
// {{std::string("\f1.23")}, FloatType(1.23)},
// {{std::string("1.23\f")}, FloatType(1.23)},
// {{std::string("\v1.23")}, FloatType(1.23)},
// {{std::string("1.23\v")}, FloatType(1.23)},
// {{std::string(" \t\n\r\f\v1.23 \t\n\r\f\v")}, FloatType(1.23)},
// // plus sign and Whitespace variations
// {{std::string(" +1.23")}, FloatType(1.23)},
// {{std::string("+1.23 ")}, FloatType(1.23)},
// {{std::string(" +1.23 ")}, FloatType(1.23)},
// {{std::string("\t+1.23")}, FloatType(1.23)},
// {{std::string("+1.23\t")}, FloatType(1.23)},
// {{std::string("\n+1.23")}, FloatType(1.23)},
// {{std::string("+1.23\n")}, FloatType(1.23)},
// {{std::string("\r+1.23")}, FloatType(1.23)},
// {{std::string("+1.23\r")}, FloatType(1.23)},
// {{std::string("\f+1.23")}, FloatType(1.23)},
// {{std::string("+1.23\f")}, FloatType(1.23)},
// {{std::string("\v+1.23")}, FloatType(1.23)},
// {{std::string("+1.23\v")}, FloatType(1.23)},
// {{std::string(" \t\n\r\f\v+1.23 \t\n\r\f\v")}, FloatType(1.23)},
// // negative value and Whitespace variations
// {{std::string(" -1.23")}, FloatType(-1.23)},
// {{std::string("-1.23 ")}, FloatType(-1.23)},
// {{std::string(" -1.23 ")}, FloatType(-1.23)},
// {{std::string("\t-1.23")}, FloatType(-1.23)},
// {{std::string("-1.23\t")}, FloatType(-1.23)},
// {{std::string("\n-1.23")}, FloatType(-1.23)},
// {{std::string("-1.23\n")}, FloatType(-1.23)},
// {{std::string("\r-1.23")}, FloatType(-1.23)},
// {{std::string("-1.23\r")}, FloatType(-1.23)},
// {{std::string("\f-1.23")}, FloatType(-1.23)},
// {{std::string("-1.23\f")}, FloatType(-1.23)},
// {{std::string("\v-1.23")}, FloatType(-1.23)},
// {{std::string("-1.23\v")}, FloatType(-1.23)},
// {{std::string(" \t\n\r\f\v-1.23 \t\n\r\f\v")}, FloatType(-1.23)},
// // Invalid cases (should throw or return error)
// /*
// {{std::string("1e")}, Exception("Incomplete exponent")},
// {{std::string("e1")}, Exception("Missing significand")},
// {{std::string(".")}, Exception("Missing digits")},
// {{std::string("+")}, Exception("Missing digits")},
// {{std::string("-")}, Exception("Missing digits")},
// {{std::string("++1")}, Exception("Multiple signs")},
// {{std::string("--1")}, Exception("Multiple signs")},
// {{std::string("+-1")}, Exception("Multiple signs")},
// {{std::string("-+1")}, Exception("Multiple signs")},
// {{std::string("1e2.3")}, Exception("Decimal in exponent")},
// {{std::string("1e2e3")}, Exception("Multiple exponents")},
// {{std::string("1e2.3e4")}, Exception("Multiple exponents")},
// */
// };
/*
std::cout << "cast string to float/double, max value:"
<< fmt::format("{}", std::numeric_limits<FloatType>::max()) << "\n";
std::cout << "cast string to float/double, -max value:"
<< fmt::format("{}", -std::numeric_limits<FloatType>::max()) << "\n";
std::cout << "cast string to float/double, min value:"
<< fmt::format("{}", std::numeric_limits<FloatType>::min()) << "\n";
std::cout << "cast string to float/double, -min value:"
<< fmt::format("{}", -std::numeric_limits<FloatType>::min()) << "\n";
std::cout << "cast string to float/double, denorm_min value:"
<< fmt::format("{}", std::numeric_limits<FloatType>::denorm_min()) << "\n";
std::cout << "cast string to float/double, -denorm_min value:"
<< fmt::format("{}", -std::numeric_limits<FloatType>::denorm_min()) << "\n";
*/
test_strs.emplace_back(fmt::format("{}", std::numeric_limits<FloatType>::max()));
test_strs.emplace_back(fmt::format("{}", std::numeric_limits<FloatType>::min()));
// test_strs.emplace_back(fmt::format("{}", std::numeric_limits<FloatType>::denorm_min()));
std::vector<std::pair<std::string, std::string>> data_pairs;
std::string table_test_expected_results;
int data_index = 0;
auto test_func = [&](bool is_negative) {
DataSet data_set;
for (const auto& v_str : test_strs) {
FloatType v {};
if constexpr (FloatPType == TYPE_FLOAT) {
v = std::strtof(v_str.data(), nullptr);
} else {
v = std::strtod(v_str.data(), nullptr);
}
if (is_negative) {
v = -v;
}
if (FLAGS_gen_regression_case) {
std::string out_str = fmt::format("{}", v);
table_test_expected_results += fmt::format("{}\t{}\n", data_index++, out_str);
if (is_negative) {
data_pairs.emplace_back("-" + v_str, out_str);
} else {
data_pairs.emplace_back(v_str, out_str);
}
}
format_decimal_number_func(data_set, v_str, v, is_negative, true, true, true);
// test leading and trailing spaces and sign
format_decimal_number_func(data_set, v_str, v, is_negative, true, true, false);
// test leading and trailing spaces and leading zeros
format_decimal_number_func(data_set, v_str, v, is_negative, true, false, true);
// test leading and trailing spaces
format_decimal_number_func(data_set, v_str, v, is_negative, true, false, false);
// test with sign and leading zeros
format_decimal_number_func(data_set, v_str, v, is_negative, false, true, true);
// test with sign
format_decimal_number_func(data_set, v_str, v, is_negative, false, true, false);
// test only leading zeros
format_decimal_number_func(data_set, v_str, v, is_negative, false, false, true);
// test strict digits
format_decimal_number_func(data_set, v_str, v, is_negative, false, false, false);
}
check_function_for_cast<DataTypeNumber<FloatPType>, false>(input_types, data_set, -1,
-1);
check_function_for_cast<DataTypeNumber<FloatPType>, true>(input_types, data_set, -1,
-1);
};
test_func(false);
test_func(true);
if (FLAGS_gen_regression_case) {
int table_index = 0;
int test_data_index = 0;
std::unique_ptr<std::ofstream> ofs_const_case_uptr, ofs_const_expected_result_uptr;
std::unique_ptr<std::ofstream> ofs_case_uptr, ofs_expected_result_uptr;
std::string cast_type_name = (FloatPType == TYPE_FLOAT ? "float" : "double");
std::string from_sql_type_name = "string";
std::string to_sql_type_name = get_sql_type_name(FloatPType);
std::string regression_case_name =
fmt::format("test_cast_to_{}_from_{}", to_sql_type_name, from_sql_type_name);
setup_regression_case_output(regression_case_name, ofs_const_case_uptr,
ofs_const_expected_result_uptr, ofs_case_uptr,
ofs_expected_result_uptr, "to_float/from_str");
auto* ofs_const_case = ofs_const_case_uptr.get();
auto* ofs_const_expected_result = ofs_const_expected_result_uptr.get();
auto* ofs_case = ofs_case_uptr.get();
auto* ofs_expected_result = ofs_expected_result_uptr.get();
gen_normal_regression_case(regression_case_name, from_sql_type_name, false,
to_sql_type_name, data_pairs, table_index++, test_data_index,
ofs_case, ofs_expected_result, ofs_const_case,
ofs_const_expected_result);
(*ofs_const_case) << "}";
(*ofs_case) << "}";
}
}
template <PrimitiveType FloatPType>
void from_string_overflow_test_func() {
InputTypeSet input_types = {PrimitiveType::TYPE_VARCHAR};
using FloatType = typename PrimitiveTypeTraits<FloatPType>::CppType;
DataSet data_set = {
// Edge values - using type-specific limits
{{std::string("1.89769e+308")}, std::numeric_limits<FloatType>::infinity()},
{{std::string("-1.89769e+308")}, -std::numeric_limits<FloatType>::infinity()},
};
// stric and non-strict mode
check_function_for_cast<DataTypeNumber<FloatPType>, true>(input_types, data_set, -1, -1);
check_function_for_cast<DataTypeNumber<FloatPType>, false>(input_types, data_set, -1, -1);
if (FLAGS_gen_regression_case) {
int table_index = 0;
std::vector<std::pair<std::string, FloatType>> data_pairs;
data_pairs.emplace_back("1.89769e+308", std::numeric_limits<FloatType>::infinity());
data_pairs.emplace_back("-1.89769e+308", -std::numeric_limits<FloatType>::infinity());
std::string table_test_expected_results;
table_test_expected_results +=
fmt::format("{}\t{}\n", 0, std::numeric_limits<FloatType>::infinity());
table_test_expected_results +=
fmt::format("{}\t{}\n", 1, -std::numeric_limits<FloatType>::infinity());
std::unique_ptr<std::ofstream> ofs_const_case_uptr, ofs_const_expected_result_uptr;
std::unique_ptr<std::ofstream> ofs_case_uptr, ofs_expected_result_uptr;
std::string from_sql_type_name = "string";
std::string to_sql_type_name = get_sql_type_name(FloatPType);
std::string regression_case_name = fmt::format("test_cast_to_{}_from_{}_overflow",
to_sql_type_name, from_sql_type_name);
setup_regression_case_output(regression_case_name, ofs_const_case_uptr,
ofs_const_expected_result_uptr, ofs_case_uptr,
ofs_expected_result_uptr, "to_float/from_str");
auto* ofs_const_case = ofs_const_case_uptr.get();
auto* ofs_const_expected_result = ofs_const_expected_result_uptr.get();
auto* ofs_case = ofs_case_uptr.get();
auto* ofs_expected_result = ofs_expected_result_uptr.get();
auto table_name = fmt::format("{}_{}", regression_case_name, table_index);
(*ofs_const_case) << " sql \"set debug_skip_fold_constant = true;\"\n";
(*ofs_case) << fmt::format(" sql \"drop table if exists {};\"\n", table_name);
(*ofs_case) << fmt::format(
" sql \"create table {}(f1 int, f2 string) "
"properties('replication_num'='1');\"\n",
table_name);
auto value_count = data_pairs.size();
auto const_test_with_strict_arg = [&](bool enable_strict_cast) {
(*ofs_const_case) << fmt::format(" sql \"set enable_strict_cast={};\"\n",
enable_strict_cast);
for (int i = 0; i != value_count; ++i) {
const auto& v_str = data_pairs[i].first;
(*ofs_const_case) << fmt::format(
" qt_sql_{}_{} \"\"\"select \"{}\", cast(\"{}\" as {});\"\"\"\n", i,
enable_strict_cast ? "strict" : "non_strict", v_str, v_str,
to_sql_type_name);
(*ofs_const_expected_result) << fmt::format(
"-- !sql_{}_{} --\n", i, enable_strict_cast ? "strict" : "non_strict");
(*ofs_const_expected_result)
<< fmt::format("{}\t{}\n\n", v_str, data_pairs[i].second);
}
};
const_test_with_strict_arg(true);
const_test_with_strict_arg(false);
(*ofs_case) << fmt::format(" sql \"\"\"insert into {} values ", table_name);
for (int i = 0; i != value_count;) {
(*ofs_case) << fmt::format("({}, \"{}\")", i, data_pairs[i].first);
++i;
if (i != value_count) {
(*ofs_case) << ",";
}
if (i % 20 == 0 && i != value_count) {
(*ofs_case) << "\n ";
}
}
(*ofs_case) << ";\n \"\"\"\n\n";
auto table_test_with_strict_arg = [&](bool enable_strict_cast) {
(*ofs_case) << fmt::format(" sql \"set enable_strict_cast={};\"\n",
enable_strict_cast);
(*ofs_case) << fmt::format(
" qt_sql_{}_{} 'select f1, cast(f2 as {}) from {} "
"order by "
"1;'\n\n",
table_index, enable_strict_cast ? "strict" : "non_strict", to_sql_type_name,
table_name);
(*ofs_expected_result) << fmt::format("-- !sql_{}_{} --\n", table_index,
enable_strict_cast ? "strict" : "non_strict");
(*ofs_expected_result) << table_test_expected_results;
(*ofs_expected_result) << "\n";
};
table_test_with_strict_arg(true);
table_test_with_strict_arg(false);
(*ofs_const_case) << "}";
(*ofs_case) << "}";
}
}
template <PrimitiveType FloatPType>
void from_string_invalid_input_test_func() {
// PG error msg: invalid input syntax for type double precision: "++123.456"
InputTypeSet input_types = {PrimitiveType::TYPE_VARCHAR};
std::vector<std::string> abnormal_inputs = {
"",
".",
" ",
"\t",
"\n",
"\r",
"\f",
"\v",
"abc",
"abc123"
"1abc12"
"123abc",
// Space between digits
"1 23",
"1\t23",
"1\n23",
"1\r23",
"1\v23",
"1\f23",
// Multiple decimal points
"1.2.3",
// invalid leading and trailing characters
"a123.456",
" a123.456",
"\ta123.456",
"\na123.456",
"\ra123.456",
"\fa123.456",
"\va123.456",
"123.456a",
"123.456a\t",
"123.456a\n",
"123.456a\r",
"123.456a\f",
"123.456a\v",
"123.456\ta",
"123.456\na",
"123.456\ra",
"123.456\fa",
"123.456\va",
// invalid char between numbers
"12a3.456",
"123a.456",
"123.a456",
"123.4a56",
// multiple positive/negative signs
"++123"
"--123"
"+-123"
"-+123"
"+-123.456",
"+- 123.456", // sign with following spaces
"-+123.456",
"++123.456",
"--123.456",
"+-.456",
"-+.456",
"++.456",
"--.456",
// hexadecimal
"0x123",
"0x123.456",
// invalid scientific notation
"e",
"-e",
"+e",
"e+",
"e-",
"e1",
"e+1",
"e-1",
".e",
"+.e",
"-.e",
".e+",
".e-",
".e+",
"1e",
"1e+",
"1e-",
"1e1a",
"1ea1",
"1e1.1",
"1e+1.1",
"1e-1.1",
// Multiple exponents
"1e2e3",
};
// non-strict mode
{
DataSet data_set;
for (const auto& input : abnormal_inputs) {
data_set.push_back({{input}, Null()});
}
check_function_for_cast<DataTypeNumber<FloatPType>, false>(input_types, data_set, -1,
-1);
}
// strict mode
using ToDataType = DataTypeNumber<FloatPType>;
for (const auto& input : abnormal_inputs) {
DataSet data_set;
data_set.push_back({{input}, Null()});
check_function_for_cast<ToDataType, true>(input_types, data_set, -1, -1, true, true);
// EXPECT_TRUE(caught_expection) << "Expected exception for input: " << input
// << ", but no exception was thrown.";
}
if (FLAGS_gen_regression_case) {
std::vector<std::string> regression_invalid_inputs = {
"",
".",
" ",
"\t",
"abc",
// Space between digits
"1 23",
"1\t23",
// Multiple decimal points
"1.2.3",
// invalid leading and trailing characters
"a123.456",
" a123.456",
"\ta123.456",
"123.456a",
"123.456a\t",
"123.456\ta",
"123.456\na",
// invalid char between numbers
"12a3.456",
"123a.456",
"123.a456",
"123.4a56",
// multiple positive/negative signs
"+-123.456",
"+- 123.456", // sign with following spaces
"-+123.456",
"++123.456",
"--123.456",
"+-.456",
"-+.456",
"++.456",
"--.456",
// hexadecimal
"0x123",
"0x123.456",
// invalid scientific notation
"e",
"-e",
"+e",
"e+",
"e-",
"e1",
"e+1",
"e-1",
".e",
"+.e",
"-.e",
".e+",
".e-",
".e+",
"1e",
"1e+",
"1e-",
"1e1a",
"1ea1",
"1e1.1",
"1e+1.1",
"1e-1.1",
// Multiple exponents
"1e2e3",
};
int table_index = 0;
std::unique_ptr<std::ofstream> ofs_const_case_uptr, ofs_const_expected_result_uptr;
std::unique_ptr<std::ofstream> ofs_case_uptr, ofs_expected_result_uptr;
// std::string cast_type_name = (FloatPType == TYPE_FLOAT ? "float" : "double");
std::string from_sql_type_name = "string";
std::string to_sql_type_name = get_sql_type_name(FloatPType);
std::string regression_case_name = fmt::format("test_cast_to_{}_from_{}_invalid",
to_sql_type_name, from_sql_type_name);
setup_regression_case_output(regression_case_name, ofs_const_case_uptr,
ofs_const_expected_result_uptr, ofs_case_uptr,
ofs_expected_result_uptr, "to_float/from_str");
auto* ofs_const_case = ofs_const_case_uptr.get();
auto* ofs_const_expected_result = ofs_const_expected_result_uptr.get();
auto* ofs_case = ofs_case_uptr.get();
auto* ofs_expected_result = ofs_expected_result_uptr.get();
gen_overflow_and_invalid_regression_case(
regression_case_name, from_sql_type_name, false, to_sql_type_name,
regression_invalid_inputs, table_index++, ofs_case, ofs_expected_result,
ofs_const_case, ofs_const_expected_result);
(*ofs_const_case) << "}";
(*ofs_case) << "}";
}
}
template <PrimitiveType IntPType, PrimitiveType FloatPType>
void from_int_test_func() {
using IntType = typename PrimitiveTypeTraits<IntPType>::CppType;
using FloatType = typename PrimitiveTypeTraits<FloatPType>::CppType;
DataTypeNumber<IntPType> dt_from;
InputTypeSet input_types = {dt_from.get_primitive_type()};
DataSet data_set = {
// Zero values
{{IntType(0)}, FloatType(0.0)},
{{IntType(-0)}, FloatType(0.0)},
// Small positive values
{{IntType(1)}, FloatType(1.0)},
{{IntType(10)}, FloatType(10.0)},
{{IntType(100)}, FloatType(100.0)},
// Small negative values
{{IntType(-1)}, FloatType(-1.0)},
{{IntType(-10)}, FloatType(-10.0)},
{{IntType(-100)}, FloatType(-100.0)},
// Powers of 2 (important for floating-point representation)
{{IntType(2)}, FloatType(2.0)},
{{IntType(4)}, FloatType(4.0)},
{{IntType(8)}, FloatType(8.0)},
{{IntType(16)}, FloatType(16.0)},
{{IntType(32)}, FloatType(32.0)},
{{IntType(64)}, FloatType(64.0)},
// {{IntType(128)}, FloatType(128.0)},
{{IntType(-2)}, FloatType(-2.0)},
{{IntType(-4)}, FloatType(-4.0)},
{{IntType(-8)}, FloatType(-8.0)},
{{IntType(-16)}, FloatType(-16.0)},
{{IntType(-32)}, FloatType(-32.0)},
{{IntType(-64)}, FloatType(-64.0)},
{{IntType(-128)}, FloatType(-128.0)},
// Edge values for each integer type
{{std::numeric_limits<IntType>::min()},
FloatType(std::numeric_limits<IntType>::min())},
{{std::numeric_limits<IntType>::max()},
FloatType(std::numeric_limits<IntType>::max())},
{{static_cast<IntType>(std::numeric_limits<IntType>::min() + 1)},
FloatType(std::numeric_limits<IntType>::min() + 1)},
{{static_cast<IntType>(std::numeric_limits<IntType>::max() - 1)},
FloatType(std::numeric_limits<IntType>::max() - 1)},
};
check_function_for_cast<DataTypeNumber<FloatPType>, false>(input_types, data_set, -1, -1);
check_function_for_cast<DataTypeNumber<FloatPType>, true>(input_types, data_set, -1, -1);
if (FLAGS_gen_regression_case) {
int table_index = 0;
int test_data_index = 0;
std::unique_ptr<std::ofstream> ofs_const_case_uptr, ofs_const_expected_result_uptr;
std::unique_ptr<std::ofstream> ofs_case_uptr, ofs_expected_result_uptr;
std::string from_type_name = get_sql_type_name(IntPType);
std::string to_type_name = get_sql_type_name(FloatPType);
std::string regression_case_name =
fmt::format("test_cast_to_{}_from_{}", to_type_name, from_type_name);
setup_regression_case_output(regression_case_name, ofs_const_case_uptr,
ofs_const_expected_result_uptr, ofs_case_uptr,
ofs_expected_result_uptr, "to_float/from_int");
auto* ofs_const_case = ofs_const_case_uptr.get();
auto* ofs_const_expected_result = ofs_const_expected_result_uptr.get();
auto* ofs_case = ofs_case_uptr.get();
auto* ofs_expected_result = ofs_expected_result_uptr.get();
std::vector<std::pair<std::string, FloatType>> regression_test_data_set;
for (const auto& p : data_set) {
regression_test_data_set.push_back(
{fmt::format("{}", any_cast<IntType>(p.first[0])),
any_cast<FloatType>(p.second)});
}
gen_normal_regression_case(regression_case_name, from_type_name, true, to_type_name,
regression_test_data_set, table_index++, test_data_index,
ofs_case, ofs_expected_result, ofs_const_case,
ofs_const_expected_result);
(*ofs_const_case) << "}";
(*ofs_case) << "}";
}
}
template <typename FromT, int FromPrecision, int FromScale, PrimitiveType FloatPType>
void from_decimal_no_overflow_test_func() {
static_assert(IsDecimalNumber<FromT>, "FromT must be a decimal type");
using FloatType = typename PrimitiveTypeTraits<FloatPType>::CppType;
DataTypeDecimal<FromT::PType> dt_from =
get_decimal_data_type<FromT>(FromPrecision, FromScale);
InputTypeSet input_types = {{dt_from.get_primitive_type(), FromScale, FromPrecision}};
auto decimal_ctor = get_decimal_ctor<FromT>();
// Compute valid ranges for integral and fractional parts
// max_integral: 99999999
// large_integral1: 9999999
// large_integral2: 90000000
// large_integral3: 90000001
constexpr auto max_integral =
decimal_scale_multiplier<typename FromT::NativeType>(FromPrecision - FromScale) - 1;
constexpr auto large_integral1 = decimal_scale_multiplier<typename FromT::NativeType>(
FromPrecision - FromScale - 1) -
1;
constexpr auto large_integral2 = max_integral - large_integral1;
constexpr auto large_integral3 =
large_integral2 > 9 ? large_integral2 + 1 : large_integral2 - 1;
// constexpr auto min_integral = -max_integral;
// std::cout << "max_integral:\t" << fmt::format("{}", max_integral) << std::endl;
// std::cout << "large_integral1:\t" << fmt::format("{}", large_integral1) << std::endl;
// std::cout << "large_integral2:\t" << fmt::format("{}", large_integral2) << std::endl;
// std::cout << "large_integral3:\t" << fmt::format("{}", large_integral3) << std::endl;
// max_fractional: 99999999
// large_fractional1: 9999999
// large_fractional2: 90000000
// large_fractional3: 90000001
constexpr auto max_fractional =
decimal_scale_multiplier<typename FromT::NativeType>(FromScale) - 1;
constexpr auto large_fractional1 =
decimal_scale_multiplier<typename FromT::NativeType>(FromScale - 1) - 1;
constexpr auto large_fractional2 = max_fractional - large_fractional1;
constexpr auto large_fractional3 =
large_fractional2 > 9 ? large_fractional2 + 1 : large_fractional2 - 1;
// std::cout << "max_fractional:\t" << fmt::format("{}", max_fractional) << std::endl;
// std::cout << "large_fractional1:\t" << fmt::format("{}", large_fractional1) << std::endl;
// std::cout << "large_fractional2:\t" << fmt::format("{}", large_fractional2) << std::endl;
// std::cout << "large_fractional3:\t" << fmt::format("{}", large_fractional3) << std::endl;
std::set<typename FromT::NativeType> integral_part = {0, max_integral};
if (max_integral > 0) {
integral_part.emplace(1);
integral_part.emplace(9);
integral_part.emplace(max_integral - 1);
integral_part.emplace(large_integral1);
integral_part.emplace(large_integral2);
integral_part.emplace(large_integral3);
}
typename FromT::NativeType from_fractional_part_multiplier = 1;
if constexpr (IsDecimalV2<FromT>) {
from_fractional_part_multiplier =
decimal_scale_multiplier<typename FromT::NativeType>(9 - FromScale);
}
std::set<typename FromT::NativeType> fractional_part = {0};
fractional_part.emplace(max_fractional * from_fractional_part_multiplier);
if (max_fractional > 0) {
fractional_part.emplace(1 * from_fractional_part_multiplier);
fractional_part.emplace(9 * from_fractional_part_multiplier);
fractional_part.emplace((max_fractional - 1) * from_fractional_part_multiplier);
fractional_part.emplace(large_fractional1 * from_fractional_part_multiplier);
fractional_part.emplace(large_fractional2 * from_fractional_part_multiplier);
fractional_part.emplace(large_fractional3 * from_fractional_part_multiplier);
}
DataSet data_set;
std::string dbg_str = fmt::format("test cast to {} from {}({}, {})\n",
std::is_same_v<FloatType, Float32> ? "float" : "double",
type_to_string(FromT::PType), FromPrecision, FromScale);
auto scale_multiplier = decimal_scale_multiplier<typename FromT::NativeType>(
IsDecimalV2<FromT> ? 9 : FromScale);
constexpr bool expect_inf =
(FromPrecision - FromScale >= 39 && std::is_same_v<FromT, Float32>);
bool have_inf = false;
std::vector<std::pair<std::string, FloatType>> test_data_set;
Defer defer {[&]() {
if (FLAGS_gen_regression_case) {
std::string from_decimal_sql_type_name =
FromT::PType == TYPE_DECIMALV2 ? "decimalv2" : "decimalv3";
std::string from_sql_type_name = fmt::format(
"{}({}, {})", from_decimal_sql_type_name, FromPrecision, FromScale);
std::string to_sql_type_name = get_sql_type_name(FloatPType);
int table_index = 0;
int test_data_index = 0;
std::unique_ptr<std::ofstream> ofs_const_case_uptr, ofs_const_expected_result_uptr;
std::unique_ptr<std::ofstream> ofs_case_uptr, ofs_expected_result_uptr;
std::string regression_case_name = fmt::format(
"test_cast_to_{}_from_{}_{}_{}", to_sql_type_name,
FromT::PType == TYPE_DECIMALV2 ? "decimalv2"
: to_lower(type_to_string(FromT::PType)),
FromPrecision, FromScale);
setup_regression_case_output(regression_case_name, ofs_const_case_uptr,
ofs_const_expected_result_uptr, ofs_case_uptr,
ofs_expected_result_uptr, "to_float/from_decimal");
auto* ofs_const_case = ofs_const_case_uptr.get();
auto* ofs_const_expected_result = ofs_const_expected_result_uptr.get();
auto* ofs_case = ofs_case_uptr.get();
auto* ofs_expected_result = ofs_expected_result_uptr.get();
if constexpr (IsDecimal256<FromT>) {
(*ofs_const_case) << " sql \"set enable_decimal256 = true;\"\n";
(*ofs_case) << " sql \"set enable_decimal256 = true;\"\n";
}
gen_normal_regression_case(regression_case_name, from_sql_type_name, true,
to_sql_type_name, test_data_set, table_index,
test_data_index, ofs_case, ofs_expected_result,
ofs_const_case, ofs_const_expected_result);
(*ofs_const_case) << "}";
(*ofs_case) << "}";
}
}};
if constexpr (FromScale == 0) {
// e.g. Decimal(9, 0), only int part
for (const auto& i : integral_part) {
auto decimal_num = decimal_ctor(i, 0, FromScale);
auto num_str = dt_from.to_string(decimal_num);
// auto float_v = static_cast<FloatType>(i);
FloatType float_v = static_cast<double>(decimal_num.value) /
static_cast<double>(scale_multiplier);
if (std::isinf(float_v)) {
// std::cout << fmt::format("cast {}({}, {}) value {} to float_v result is inf\n",
// type_to_string(FromT::PType), FromPrecision, FromScale,
// dt.to_string(decimal_num));
have_inf = true;
}
// dbg_str += fmt::format("({}, {})|", dt.to_string(decimal_num), float_v);
data_set.push_back({{decimal_num}, float_v});
test_data_set.emplace_back(num_str, float_v);
decimal_num = decimal_ctor(-i, 0, FromScale);
num_str = dt_from.to_string(decimal_num);
float_v = static_cast<double>(decimal_num.value) /
static_cast<double>(scale_multiplier);
if (std::isinf(float_v)) {
// std::cout << fmt::format("cast {}({}, {}) value {} to float_v result is inf\n",
// type_to_string(FromT::PType), FromPrecision, FromScale,
// dt.to_string(decimal_num));
have_inf = true;
}
// dbg_str += fmt::format("({}, {})|", dt.to_string(decimal_num), -i);
data_set.push_back({{decimal_num}, FloatType(-i)});
test_data_set.emplace_back(num_str, FloatType(-i));
}
// std::cout << dbg_str << std::endl;
check_function_for_cast<DataTypeNumber<FloatPType>, true>(input_types, data_set, -1,
-1);
check_function_for_cast<DataTypeNumber<FloatPType>, false>(input_types, data_set, -1,
-1);
return;
} else if constexpr (FromScale == FromPrecision) {
// e.g. Decimal(9, 9), only fraction part
for (const auto& f : fractional_part) {
auto decimal_num = decimal_ctor(0, f, FromScale);
auto num_str = dt_from.to_string(decimal_num);
FloatType float_v = static_cast<double>(decimal_num.value) /
static_cast<double>(scale_multiplier);
// dbg_str += fmt::format("({}, {})|", dt.to_string(decimal_num), float_v);
data_set.push_back({{decimal_num}, float_v});
test_data_set.emplace_back(num_str, float_v);
decimal_num = decimal_ctor(0, -f, FromScale);
num_str = dt_from.to_string(decimal_num);
float_v = static_cast<double>(decimal_num.value) /
static_cast<double>(scale_multiplier);
// dbg_str += fmt::format("({}, {})|", dt.to_string(decimal_num), float_v);
data_set.push_back({{decimal_num}, float_v});
test_data_set.emplace_back(num_str, float_v);
}
// std::cout << dbg_str << std::endl;
check_function_for_cast<DataTypeNumber<FloatPType>, true>(input_types, data_set, -1,
-1);
check_function_for_cast<DataTypeNumber<FloatPType>, false>(input_types, data_set, -1,
-1);
return;
}
for (const auto& i : integral_part) {
for (const auto& f : fractional_part) {
auto decimal_num = decimal_ctor(i, f, FromScale);
auto num_str = dt_from.to_string(decimal_num);
FloatType float_v = static_cast<double>(decimal_num.value) /
static_cast<double>(scale_multiplier);
if (std::isinf(float_v)) {
// std::cout << fmt::format("cast {}({}, {}) value {} to float_v result is inf\n",
// type_to_string(FromT::PType), FromPrecision, FromScale,
// dt.to_string(decimal_num));
have_inf = true;
}
// dbg_str += fmt::format("({}, {})|", dt.to_string(decimal_num), float_v);
data_set.push_back({{decimal_num}, float_v});
test_data_set.emplace_back(num_str, float_v);
decimal_num = decimal_ctor(-i, -f, FromScale);
num_str = dt_from.to_string(decimal_num);
float_v = static_cast<double>(decimal_num.value) /
static_cast<double>(scale_multiplier);
if (std::isinf(float_v)) {
// std::cout << fmt::format("cast {}({}, {}) value {} to float_v result is inf\n",
// type_to_string(FromT::PType), FromPrecision, FromScale,
// dt.to_string(decimal_num));
have_inf = true;
}
// dbg_str += fmt::format("({}, {})|", dt.to_string(decimal_num), float_v);
data_set.push_back({{decimal_num}, float_v});
test_data_set.emplace_back(num_str, float_v);
}
// dbg_str += "\n";
}
// std::cout << dbg_str << std::endl;
if constexpr (expect_inf) {
EXPECT_TRUE(have_inf);
}
check_function_for_cast<DataTypeNumber<FloatPType>, true>(input_types, data_set, -1, -1);
check_function_for_cast<DataTypeNumber<FloatPType>, false>(input_types, data_set, -1, -1);
}
template <typename FromT, PrimitiveType ToPT>
void from_decimal_test_func() {
constexpr auto max_decimal_pre = max_decimal_precision<FromT::PType>();
constexpr auto min_decimal_pre =
std::is_same_v<FromT, Decimal32>
? 1
: (std::is_same_v<FromT, Decimal64>
? BeConsts::MAX_DECIMAL32_PRECISION + 1
: (std::is_same_v<FromT, Decimal128V3>
? BeConsts::MAX_DECIMAL64_PRECISION + 1
: (std::is_same_v<FromT, Decimal256>
? BeConsts::MAX_DECIMAL128_PRECISION + 1
: 1)));
static_assert(min_decimal_pre == 1 || min_decimal_pre > 9);
if constexpr (std::is_same_v<FromT, Decimal128V2>) {
from_decimal_no_overflow_test_func<FromT, 1, 0, ToPT>();
from_decimal_no_overflow_test_func<FromT, 1, 1, ToPT>();
from_decimal_no_overflow_test_func<FromT, 27, 9, ToPT>();
from_decimal_no_overflow_test_func<FromT, 20, 6, ToPT>();
} else {
from_decimal_no_overflow_test_func<FromT, min_decimal_pre, 0, ToPT>();
if constexpr (min_decimal_pre != 1) {
from_decimal_no_overflow_test_func<FromT, min_decimal_pre, min_decimal_pre / 2,
ToPT>();
from_decimal_no_overflow_test_func<FromT, min_decimal_pre, min_decimal_pre - 1,
ToPT>();
}
from_decimal_no_overflow_test_func<FromT, min_decimal_pre, min_decimal_pre, ToPT>();
from_decimal_no_overflow_test_func<FromT, max_decimal_pre, 0, ToPT>();
from_decimal_no_overflow_test_func<FromT, max_decimal_pre, 1, ToPT>();
from_decimal_no_overflow_test_func<FromT, max_decimal_pre, max_decimal_pre / 2, ToPT>();
from_decimal_no_overflow_test_func<FromT, max_decimal_pre, max_decimal_pre - 1, ToPT>();
from_decimal_no_overflow_test_func<FromT, max_decimal_pre, max_decimal_pre, ToPT>();
}
}
template <int FromPrecision, int FromScale>
void from_decimalv3_overflow_test_func(const std::string& regression_case_name, int table_index,
int& test_data_index, std::ofstream* ofs_case,
std::ofstream* ofs_expected_result,
std::ofstream* ofs_const_case,
std::ofstream* ofs_const_expected_result) {
using FromT = Decimal256;
using FloatType = float;
DataTypeDecimal<TYPE_DECIMAL256> dt_from(FromPrecision, FromScale);
InputTypeSet input_types = {{TYPE_DECIMAL256, FromScale, FromPrecision}};
auto decimal_ctor = get_decimal_ctor<FromT>();
constexpr auto max_integral =
decimal_scale_multiplier<typename FromT::NativeType>(FromPrecision - FromScale) - 1;
constexpr auto large_integral1 = decimal_scale_multiplier<typename FromT::NativeType>(
FromPrecision - FromScale - 1) -
1;
constexpr auto large_integral2 = max_integral - large_integral1;
constexpr auto large_integral3 =
large_integral2 > 9 ? large_integral2 + 1 : large_integral2 - 1;
// std::cout << "max_integral:\t" << fmt::format("{}", max_integral) << std::endl;
// std::cout << "large_integral1:\t" << fmt::format("{}", large_integral1) << std::endl;
// std::cout << "large_integral2:\t" << fmt::format("{}", large_integral2) << std::endl;
// std::cout << "large_integral3:\t" << fmt::format("{}", large_integral3) << std::endl;
constexpr auto max_fractional =
decimal_scale_multiplier<typename FromT::NativeType>(FromScale) - 1;
constexpr auto large_fractional1 =
decimal_scale_multiplier<typename FromT::NativeType>(FromScale - 1) - 1;
constexpr auto large_fractional2 = max_fractional - large_fractional1;
constexpr auto large_fractional3 =
large_fractional2 > 9 ? large_fractional2 + 1 : large_fractional2 - 1;
// std::cout << "max_fractional:\t" << fmt::format("{}", max_fractional) << std::endl;
// std::cout << "large_fractional1:\t" << fmt::format("{}", large_fractional1) << std::endl;
// std::cout << "large_fractional2:\t" << fmt::format("{}", large_fractional2) << std::endl;
// std::cout << "large_fractional3:\t" << fmt::format("{}", large_fractional3) << std::endl;
std::set<typename FromT::NativeType> integral_part = {max_integral, large_integral2,
large_integral3};
std::set<typename FromT::NativeType> fractional_part = {
0, max_fractional, large_fractional1, large_fractional2, large_fractional3,
};
DataSet data_set;
std::string dbg_str = fmt::format("test cast to {} from {}({}, {}) overflow\n",
std::is_same_v<FloatType, Float32> ? "float" : "double",
type_to_string(FromT::PType), FromPrecision, FromScale);
std::vector<std::pair<std::string, FloatType>> test_data_set;
Defer defer {[&]() {
if (FLAGS_gen_regression_case) {
std::string from_sql_type_name =
fmt::format("decimalv3({}, {})", FromPrecision, FromScale);
std::string to_sql_type_name = "float";
gen_normal_regression_case(regression_case_name, from_sql_type_name, true,
to_sql_type_name, test_data_set, table_index,
test_data_index, ofs_case, ofs_expected_result,
ofs_const_case, ofs_const_expected_result);
}
}};
if constexpr (FromScale == 0) {
// e.g. Decimal(76, 0), only int part
for (const auto& i : integral_part) {
auto decimal_num = decimal_ctor(i, 0, FromScale);
auto num_str = dt_from.to_string(decimal_num);
// dbg_str += fmt::format("{}, ", num_str);
data_set.push_back({{decimal_num}, std::numeric_limits<FloatType>::infinity()});
test_data_set.emplace_back(num_str, std::numeric_limits<FloatType>::infinity());
decimal_num = decimal_ctor(-i, 0, FromScale);
num_str = dt_from.to_string(decimal_num);
// dbg_str += fmt::format("{}, ", num_str);
data_set.push_back({{decimal_num}, -std::numeric_limits<FloatType>::infinity()});
test_data_set.emplace_back(num_str, -std::numeric_limits<FloatType>::infinity());
}
// dbg_str += "\n";
// std::cout << dbg_str << std::endl;
check_function_for_cast<DataTypeNumber<TYPE_FLOAT>, true>(input_types, data_set, -1,
-1);
check_function_for_cast<DataTypeNumber<TYPE_FLOAT>, false>(input_types, data_set, -1,
-1);
return;
} else if constexpr (FromScale == FromPrecision) {
return;
}
for (const auto& i : integral_part) {
for (const auto& f : fractional_part) {
auto decimal_num = decimal_ctor(i, f, FromScale);
auto num_str = dt_from.to_string(decimal_num);
// dbg_str += fmt::format("{}, ", num_str);
data_set.push_back({{decimal_num}, std::numeric_limits<FloatType>::infinity()});
test_data_set.emplace_back(num_str, std::numeric_limits<FloatType>::infinity());
decimal_num = decimal_ctor(-i, -f, FromScale);
num_str = dt_from.to_string(decimal_num);
// dbg_str += fmt::format("{}, ", num_str);
data_set.push_back({{decimal_num}, -std::numeric_limits<FloatType>::infinity()});
test_data_set.emplace_back(num_str, -std::numeric_limits<FloatType>::infinity());
}
// dbg_str += "\n";
}
// std::cout << dbg_str << std::endl;
check_function_for_cast<DataTypeNumber<TYPE_FLOAT>, true>(input_types, data_set, -1, -1);
check_function_for_cast<DataTypeNumber<TYPE_FLOAT>, false>(input_types, data_set, -1, -1);
}
void from_decimal_overflow_test_func() {
constexpr auto max_decimal_pre = max_decimal_precision<TYPE_DECIMAL256>();
constexpr auto min_decimal_pre = BeConsts::MAX_DECIMAL128_PRECISION + 1;
int table_index = 0;
int test_data_index = 0;
std::unique_ptr<std::ofstream> ofs_const_case_uptr, ofs_const_expected_result_uptr;
std::unique_ptr<std::ofstream> ofs_case_uptr, ofs_expected_result_uptr;
std::string regression_case_name = "test_cast_to_float_from_decimal256_overflow";
if (FLAGS_gen_regression_case) {
setup_regression_case_output(regression_case_name, ofs_const_case_uptr,
ofs_const_expected_result_uptr, ofs_case_uptr,
ofs_expected_result_uptr, "to_float/from_decimal");
}
auto* ofs_const_case = ofs_const_case_uptr.get();
auto* ofs_const_expected_result = ofs_const_expected_result_uptr.get();
auto* ofs_case = ofs_case_uptr.get();
auto* ofs_expected_result = ofs_expected_result_uptr.get();
if (FLAGS_gen_regression_case) {
(*ofs_const_case) << " sql \"set debug_skip_fold_constant = true;\"\n";
(*ofs_const_case) << " sql \"set enable_decimal256 = true;\"\n";
(*ofs_case) << " sql \"set enable_decimal256 = true;\"\n";
}
from_decimalv3_overflow_test_func<min_decimal_pre, 0>(
regression_case_name, table_index++, test_data_index, ofs_case, ofs_expected_result,
ofs_const_case, ofs_const_expected_result);
from_decimalv3_overflow_test_func<min_decimal_pre + 1, 0>(
regression_case_name, table_index++, test_data_index, ofs_case, ofs_expected_result,
ofs_const_case, ofs_const_expected_result);
from_decimalv3_overflow_test_func<min_decimal_pre + 1, 1>(
regression_case_name, table_index++, test_data_index, ofs_case, ofs_expected_result,
ofs_const_case, ofs_const_expected_result);
from_decimalv3_overflow_test_func<60, 0>(regression_case_name, table_index++,
test_data_index, ofs_case, ofs_expected_result,
ofs_const_case, ofs_const_expected_result);
from_decimalv3_overflow_test_func<60, 20>(regression_case_name, table_index++,
test_data_index, ofs_case, ofs_expected_result,
ofs_const_case, ofs_const_expected_result);
from_decimalv3_overflow_test_func<max_decimal_pre, 0>(
regression_case_name, table_index++, test_data_index, ofs_case, ofs_expected_result,
ofs_const_case, ofs_const_expected_result);
from_decimalv3_overflow_test_func<max_decimal_pre, 1>(
regression_case_name, table_index++, test_data_index, ofs_case, ofs_expected_result,
ofs_const_case, ofs_const_expected_result);
from_decimalv3_overflow_test_func<max_decimal_pre, 10>(
regression_case_name, table_index++, test_data_index, ofs_case, ofs_expected_result,
ofs_const_case, ofs_const_expected_result);
from_decimalv3_overflow_test_func<max_decimal_pre, 37>(
regression_case_name, table_index++, test_data_index, ofs_case, ofs_expected_result,
ofs_const_case, ofs_const_expected_result);
if (FLAGS_gen_regression_case) {
(*ofs_const_case) << "}";
(*ofs_case) << "}";
}
}
template <PrimitiveType FloatPType>
void from_date_test_func() {
using FloatType = typename PrimitiveTypeTraits<FloatPType>::CppType;
InputTypeSet input_types = {PrimitiveType::TYPE_DATEV2};
std::vector<uint16_t> years = {0, 1, 10, 100, 2025, 9999};
std::vector<uint8_t> months = {1, 12};
std::vector<uint8_t> days = {1, 10, 28};
DataTypeDateV2 dt;
std::string to_sql_type_name = get_sql_type_name(FloatPType);
std::string dbg_str = fmt::format("test cast to {} from date\n", to_sql_type_name);
DataSet data_set;
std::vector<std::pair<std::string, FloatType>> regression_test_data_set;
for (auto year : years) {
for (auto month : months) {
for (auto day : days) {
DateV2Value<DateV2ValueType> date_val(year, month, day, 0, 0, 0, 0);
FloatType expect_cast_result = year * 10000 + month * 100 + day;
// dbg_str += fmt::format("({}, {})|", dt.to_string(date_val.to_date_int_val()),
// expect_cast_result);
data_set.push_back({{date_val}, expect_cast_result});
if (FLAGS_gen_regression_case) {
regression_test_data_set.push_back(
{dt.to_string(date_val.to_date_int_val()), expect_cast_result});
}
{
DataSet data_set_tmp;
data_set_tmp.push_back({{date_val}, expect_cast_result});
check_function_for_cast<DataTypeNumber<FloatPType>, true>(
input_types, data_set_tmp, -1, -1, false, true);
}
}
}
// dbg_str += "\n";
}
// std::cout << dbg_str << std::endl;
check_function_for_cast<DataTypeNumber<FloatPType>, false>(input_types, data_set, -1, -1,
false);
if (FLAGS_gen_regression_case) {
int table_index = 0;
int test_data_index = 0;
std::unique_ptr<std::ofstream> ofs_const_case_uptr, ofs_const_expected_result_uptr;
std::unique_ptr<std::ofstream> ofs_case_uptr, ofs_expected_result_uptr;
std::string from_sql_type_name = "datev2";
std::string regression_case_name =
fmt::format("test_cast_to_{}_from_{}", to_sql_type_name, from_sql_type_name);
setup_regression_case_output(regression_case_name, ofs_const_case_uptr,
ofs_const_expected_result_uptr, ofs_case_uptr,
ofs_expected_result_uptr, "to_float/from_datetime", false);
auto* ofs_const_case = ofs_const_case_uptr.get();
auto* ofs_const_expected_result = ofs_const_expected_result_uptr.get();
auto* ofs_case = ofs_case_uptr.get();
auto* ofs_expected_result = ofs_expected_result_uptr.get();
gen_normal_regression_case(regression_case_name, from_sql_type_name, true,
to_sql_type_name, regression_test_data_set, table_index++,
test_data_index, ofs_case, ofs_expected_result,
ofs_const_case, ofs_const_expected_result, false, true,
true);
// (*ofs_const_case) << "}";
(*ofs_case) << "}";
}
}
template <PrimitiveType FloatPType, int Scale>
void from_datetime_test_func() {
using FloatType = typename PrimitiveTypeTraits<FloatPType>::CppType;
InputTypeSet input_types = {{PrimitiveType::TYPE_DATETIMEV2, Scale}};
std::vector<uint16_t> years = {0, 1, 10, 100, 2025, 9999};
std::vector<uint8_t> months = {1, 12};
std::vector<uint8_t> days = {1, 28};
std::vector<uint8_t> hours = {0, 1, 23};
std::vector<uint8_t> minutes = {0, 1, 59};
std::vector<uint8_t> seconds = {0, 1, 59};
std::vector<uint32_t> mircoseconds = {0, 1, 999999};
DataTypeDateTimeV2 dt(Scale);
std::string to_sql_type_name = get_sql_type_name(FloatPType);
std::string dbg_str =
fmt::format("test cast to {} from datetimev2({})\n", Scale, to_sql_type_name);
DataSet data_set;
std::vector<std::pair<std::string, FloatType>> regression_test_data_set;
for (auto year : years) {
for (auto month : months) {
for (auto day : days) {
for (auto hour : hours) {
for (auto minute : minutes) {
for (auto second : seconds) {
for (auto microsecond : mircoseconds) {
DateV2Value<DateTimeV2ValueType> date_val(
year, month, day, hour, minute, second, microsecond);
FloatType expect_cast_result =
(year * 10000L + month * 100 + day) * 1000000L +
hour * 10000 + minute * 100 + second;
// dbg_str += fmt::format("({}, {})|",
// dt.to_string(date_val.to_date_int_val()),
// expect_cast_result);
data_set.push_back({{date_val}, expect_cast_result});
if (FLAGS_gen_regression_case) {
regression_test_data_set.push_back(
{dt.to_string(date_val.to_date_int_val()),
expect_cast_result});
}
{
DataSet data_set_tmp;
data_set_tmp.push_back({{date_val}, expect_cast_result});
check_function_for_cast<DataTypeNumber<FloatPType>, true>(
input_types, data_set_tmp, -1, -1, false, true);
}
}
}
}
}
// dbg_str += "\n";
}
}
}
// std::cout << dbg_str << std::endl;
check_function_for_cast<DataTypeNumber<FloatPType>, false>(input_types, data_set, -1, -1,
false);
if (FLAGS_gen_regression_case) {
int table_index = 0;
int test_data_index = 0;
auto test_data_total_row_count = regression_test_data_set.size();
size_t num_pieces = 10;
size_t regression_case_avg_row_count =
(test_data_total_row_count + num_pieces - 1) / num_pieces;
for (size_t piece = 0; piece < num_pieces; ++piece) {
size_t data_index = piece * regression_case_avg_row_count;
if (data_index >= test_data_total_row_count) {
break;
}
size_t regression_case_row_count = regression_case_avg_row_count;
if (data_index + regression_case_row_count > test_data_total_row_count) {
regression_case_row_count = test_data_total_row_count - data_index;
}
std::unique_ptr<std::ofstream> ofs_const_case_uptr, ofs_const_expected_result_uptr;
std::unique_ptr<std::ofstream> ofs_case_uptr, ofs_expected_result_uptr;
std::string from_sql_type_name = fmt::format("datetimev2({})", Scale);
std::string regression_case_name =
fmt::format("test_cast_to_{}_from_datetimev2_{}_part{}", to_sql_type_name,
Scale, piece);
setup_regression_case_output(
regression_case_name, ofs_const_case_uptr, ofs_const_expected_result_uptr,
ofs_case_uptr, ofs_expected_result_uptr, "to_float/from_datetime", false);
auto* ofs_const_case = ofs_const_case_uptr.get();
auto* ofs_const_expected_result = ofs_const_expected_result_uptr.get();
auto* ofs_case = ofs_case_uptr.get();
auto* ofs_expected_result = ofs_expected_result_uptr.get();
std::vector<std::pair<std::string, FloatType>> piece_data(
regression_test_data_set.begin() + data_index,
regression_test_data_set.begin() + data_index + regression_case_row_count);
gen_normal_regression_case(
regression_case_name, from_sql_type_name, true, to_sql_type_name,
piece_data, table_index++, test_data_index, ofs_case, ofs_expected_result,
ofs_const_case, ofs_const_expected_result, false, true, true);
// (*ofs_const_case) << "}";
(*ofs_case) << "}";
}
}
}
template <PrimitiveType ToPT>
void from_time_test_func() {
using ToT = typename PrimitiveTypeTraits<ToPT>::CppType;
InputTypeSet input_types = {{PrimitiveType::TYPE_TIMEV2, 6}};
std::vector<int64_t> hours = {0, 1, 10, 100, 838};
std::vector<int64_t> minutes = {0, 1, 10, 59};
std::vector<int64_t> seconds = {0, 1, 10, 59};
std::string to_sql_type_name = get_sql_type_name(ToPT);
std::string dbg_str = fmt::format("test cast to {} from time\n", to_sql_type_name);
std::vector<std::pair<std::string, ToT>> regression_test_data_set;
auto test_func = [&](bool negative) {
DataSet data_set;
for (auto h : hours) {
for (auto m : minutes) {
for (auto s : seconds) {
auto time_val = doris::TimeValue::make_time(h, m, s, negative);
auto expect_cast_result = static_cast<ToT>(time_val);
data_set.push_back({{time_val}, expect_cast_result});
// dbg_str +=
// fmt::format("({}, {})|", doris::TimeValue::to_string(time_val, 6),
// expect_cast_result);
if (FLAGS_gen_regression_case) {
regression_test_data_set.emplace_back(
doris::TimeValue::to_string(time_val, 6), expect_cast_result);
}
{
DataSet data_set_tmp;
data_set_tmp.push_back({{time_val}, expect_cast_result});
check_function_for_cast<DataTypeNumber<ToPT>, true>(
input_types, data_set_tmp, -1, -1, false, true);
}
}
}
}
// std::cout << dbg_str << std::endl;
check_function_for_cast<DataTypeNumber<ToPT>, false>(input_types, data_set, -1, -1,
false);
};
test_func(false);
test_func(true);
/*
if (FLAGS_gen_regression_case) {
int table_index = 0;
int test_data_index = 0;
std::unique_ptr<std::ofstream> ofs_const_case_uptr, ofs_const_expected_result_uptr;
std::unique_ptr<std::ofstream> ofs_case_uptr, ofs_expected_result_uptr;
std::string from_sql_type_name = "time";
std::string regression_case_name =
fmt::format("test_cast_to_{}_from_{}", to_sql_type_name, from_sql_type_name);
setup_regression_case_output(
regression_case_name, ofs_const_case_uptr, ofs_const_expected_result_uptr,
ofs_case_uptr, ofs_expected_result_uptr, "to_float/from_datetime", true, false);
auto* ofs_const_case = ofs_const_case_uptr.get();
auto* ofs_const_expected_result = ofs_const_expected_result_uptr.get();
auto* ofs_case = ofs_case_uptr.get();
auto* ofs_expected_result = ofs_expected_result_uptr.get();
gen_normal_regression_case(regression_case_name, from_sql_type_name, true,
to_sql_type_name, regression_test_data_set, table_index++,
test_data_index, ofs_case, ofs_expected_result,
ofs_const_case, ofs_const_expected_result, true, false,
true);
(*ofs_const_case) << "}";
}
*/
}
};
/*
<float> ::= <whitespace>* <value> <whitespace>*
<whitespace> ::= " " | "\t" | "\n" | "\r" | "\f" | "\v"
<value> ::= <decimal> | <infinity> | <nan>
<decimal> ::= <sign>? <significand> <exponent>?
<infinity> ::= <sign>? <inf_literal>
<nan> ::= <sign>? <nan_literal>
<sign> ::= "+" | "-"
<significand> ::= <digits> | <digits> "." <digits> | <digits> "." | "." <digits>
<digits> ::= <digit>+
<digit> ::= "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
<exponent> ::= <e_marker> <sign>? <digits>
<e_marker> ::= "e" | "E"
<inf_literal> ::= <"INF" case-insensitive> | <"INFINITY" case-insensitive>
<nan_literal> ::= <"NAN" case-insensitive>
*/
TEST_F(FunctionCastToFloatTest, test_from_string) {
from_string_test_func<TYPE_FLOAT>();
from_string_test_func<TYPE_DOUBLE>();
}
TEST_F(FunctionCastToFloatTest, test_from_string_overflow) {
from_string_overflow_test_func<TYPE_FLOAT>();
from_string_overflow_test_func<TYPE_DOUBLE>();
}
TEST_F(FunctionCastToFloatTest, test_from_string_invalid_input) {
from_string_invalid_input_test_func<TYPE_FLOAT>();
from_string_invalid_input_test_func<TYPE_DOUBLE>();
}
TEST_F(FunctionCastToFloatTest, test_from_bool) {
InputTypeSet input_types = {PrimitiveType::TYPE_BOOLEAN};
{
DataSet data_set = {
{{UInt8 {0}}, Float32(0)},
{{UInt8 {1}}, Float32(1)},
};
check_function_for_cast<DataTypeFloat32, false>(input_types, data_set, -1, -1);
check_function_for_cast<DataTypeFloat32, true>(input_types, data_set, -1, -1);
}
{
DataSet data_set = {
{{UInt8 {0}}, Float64(0)},
{{UInt8 {1}}, Float64(1)},
};
check_function_for_cast<DataTypeFloat64, false>(input_types, data_set, -1, -1);
check_function_for_cast<DataTypeFloat64, true>(input_types, data_set, -1, -1);
}
}
TEST_F(FunctionCastToFloatTest, test_from_int) {
// Test Int8 to Float32/Float64
from_int_test_func<TYPE_TINYINT, TYPE_FLOAT>();
from_int_test_func<TYPE_TINYINT, TYPE_DOUBLE>();
// Test Int16 to Float32/Float64
from_int_test_func<TYPE_SMALLINT, TYPE_FLOAT>();
from_int_test_func<TYPE_SMALLINT, TYPE_DOUBLE>();
// Test Int32 to Float32/Float64
from_int_test_func<TYPE_INT, TYPE_FLOAT>();
from_int_test_func<TYPE_INT, TYPE_DOUBLE>();
// Test Int64 to Float32/Float64
from_int_test_func<TYPE_BIGINT, TYPE_FLOAT>();
from_int_test_func<TYPE_BIGINT, TYPE_DOUBLE>();
// Test Int128 to Float32/Float64
from_int_test_func<TYPE_LARGEINT, TYPE_FLOAT>();
from_int_test_func<TYPE_LARGEINT, TYPE_DOUBLE>();
}
TEST_F(FunctionCastToFloatTest, test_from_float_to_double) {
InputTypeSet input_types = {PrimitiveType::TYPE_FLOAT};
DataSet data_set = {
// Zero and sign variations
{{Float32(0)}, Float64(0.0)},
{{Float32(+0)}, Float64(0.0)},
{{Float32(-0)}, Float64(-0.0)},
{{Float32(0.0)}, Float64(0.0)},
{{Float32(+0.0)}, Float64(0.0)},
{{Float32(-0.0)}, Float64(-0.0)},
{{Float32(.0)}, Float64(0.0)},
{{Float32(+.0)}, Float64(0.0)},
{{Float32(-.0)}, Float64(-0.0)},
// Normal positive values
{{Float32(1)}, Float64(1.0)},
{{Float32(123)}, Float64(123.0)},
{{Float32(1.23)}, Float64(Float32(1.23))},
{{Float32(123.456)}, Float64(Float32(123.456))},
{{Float32(1.23456)}, Float64(Float32(1.23456))},
{{Float32(0.123456)}, Float64(Float32(0.123456))},
{{Float32(.123456)}, Float64(Float32(0.123456))},
// Normal negative values
{{Float32(-1)}, Float64(-1.0)},
{{Float32(-123)}, Float64(-123.0)},
{{Float32(-1.23)}, Float64(Float32(-1.23))},
{{Float32(-123.456)}, Float64(Float32(-123.456))},
{{Float32(-1.23456)}, Float64(Float32(-1.23456))},
{{Float32(-0.123456)}, Float64(Float32(-0.123456))},
{{Float32(-.123456)}, Float64(Float32(-0.123456))},
// Scientific notation (exponent)
{{Float32(1e0)}, Float64(1.0)},
{{Float32(1e1)}, Float64(10.0)},
{{Float32(1e-1)}, Float64(Float32(0.1))},
{{Float32(1.23e2)}, Float64(123.0)},
{{Float32(1.23e-2)}, Float64(Float32(0.0123))},
{{Float32(1.23E2)}, Float64(123.0)},
{{Float32(1.23E-2)}, Float64(Float32(0.0123))},
{{Float32(-1.23e2)}, Float64(-123.0)},
{{Float32(-1.23e-2)}, Float64(Float32(-0.0123))},
// Infinity values
{{std::numeric_limits<Float32>::infinity()}, std::numeric_limits<Float64>::infinity()},
// NaN values
{{std::numeric_limits<Float32>::quiet_NaN()},
std::numeric_limits<Float64>::quiet_NaN()},
// Edge values
// {{Float32(1.7976931348623157e+308)},
// Float64(std::numeric_limits<double>::max())},
// {{Float32(-1.7976931348623157e+308)},
// Float64(-std::numeric_limits<double>::max())},
// {{Float32(2.2250738585072014e-308)},
// Float64(std::numeric_limits<double>::min())},
// {{Float32(-2.2250738585072014e-308)},
// Float64(-std::numeric_limits<double>::min())},
// Edge values - using type-specific limits
{{std::numeric_limits<Float32>::max()}, Float64(std::numeric_limits<Float32>::max())},
{{-std::numeric_limits<Float32>::max()}, Float64(-std::numeric_limits<Float32>::max())},
{{std::numeric_limits<Float32>::min()}, Float64(std::numeric_limits<Float32>::min())},
{{-std::numeric_limits<Float32>::min()}, Float64(-std::numeric_limits<Float32>::min())},
// Very small values
{{std::numeric_limits<Float32>::denorm_min()},
Float64(std::numeric_limits<Float32>::denorm_min())},
{{-std::numeric_limits<Float32>::denorm_min()},
Float64(-std::numeric_limits<Float32>::denorm_min())},
};
check_function_for_cast<DataTypeFloat64, false>(input_types, data_set, -1, -1);
check_function_for_cast<DataTypeFloat64, true>(input_types, data_set, -1, -1);
}
TEST_F(FunctionCastToFloatTest, test_from_double_to_float) {
InputTypeSet input_types = {PrimitiveType::TYPE_DOUBLE};
DataSet data_set = {
// Zero and sign variations
{{Float64(0)}, Float32(0.0)},
{{Float64(+0)}, Float32(0.0)},
{{Float64(-0)}, Float32(-0.0)},
{{Float64(0.0)}, Float32(0.0)},
{{Float64(+0.0)}, Float32(0.0)},
{{Float64(-0.0)}, Float32(-0.0)},
{{Float64(.0)}, Float32(0.0)},
{{Float64(+.0)}, Float32(0.0)},
{{Float64(-.0)}, Float32(-0.0)},
// Normal positive values
{{Float64(1)}, Float32(1.0)},
{{Float64(123)}, Float32(123.0)},
{{Float64(1.23)}, Float32(Float64(1.23))},
{{Float64(123.456)}, Float32(Float64(123.456))},
{{Float64(1.23456)}, Float32(Float64(1.23456))},
{{Float64(0.123456)}, Float32(Float64(0.123456))},
{{Float64(.123456)}, Float32(Float64(0.123456))},
// Normal negative values
{{Float64(-1)}, Float32(-1.0)},
{{Float64(-123)}, Float32(-123.0)},
{{Float64(-1.23)}, Float32(Float64(-1.23))},
{{Float64(-123.456)}, Float32(Float64(-123.456))},
{{Float64(-1.23456)}, Float32(Float64(-1.23456))},
{{Float64(-0.123456)}, Float32(Float64(-0.123456))},
{{Float64(-.123456)}, Float32(Float64(-0.123456))},
// Scientific notation (exponent)
{{Float64(1e0)}, Float32(1.0)},
{{Float64(1e1)}, Float32(10.0)},
{{Float64(1e-1)}, Float32(Float64(0.1))},
{{Float64(1.23e2)}, Float32(123.0)},
{{Float64(1.23e-2)}, Float32(Float64(0.0123))},
{{Float64(1.23E2)}, Float32(123.0)},
{{Float64(1.23E-2)}, Float32(Float64(0.0123))},
{{Float64(-1.23e2)}, Float32(-123.0)},
{{Float64(-1.23e-2)}, Float32(Float64(-0.0123))},
// Infinity values
{{std::numeric_limits<Float64>::infinity()}, std::numeric_limits<Float32>::infinity()},
// NaN values
{{std::numeric_limits<Float64>::quiet_NaN()},
std::numeric_limits<Float32>::quiet_NaN()},
// Edge values - using type-specific limits
{{Float64(std::numeric_limits<Float32>::max())}, std::numeric_limits<Float32>::max()},
{{Float64(-std::numeric_limits<Float32>::max())}, -std::numeric_limits<Float32>::max()},
{{Float64(std::numeric_limits<Float32>::min())}, std::numeric_limits<Float32>::min()},
{{Float64(-std::numeric_limits<Float32>::min())}, -std::numeric_limits<Float32>::min()},
// overflow
{{std::numeric_limits<Float64>::max()}, std::numeric_limits<Float32>::infinity()},
// Very small values
{{Float64(std::numeric_limits<Float32>::denorm_min())},
Float32(std::numeric_limits<Float32>::denorm_min())},
{{Float64(-std::numeric_limits<Float32>::denorm_min())},
Float32(-std::numeric_limits<Float32>::denorm_min())},
};
check_function_for_cast<DataTypeFloat32, false>(input_types, data_set, -1, -1);
check_function_for_cast<DataTypeFloat32, true>(input_types, data_set, -1, -1);
}
TEST_F(FunctionCastToFloatTest, test_from_decimal) {
from_decimal_test_func<Decimal32, TYPE_FLOAT>();
from_decimal_test_func<Decimal64, TYPE_FLOAT>();
from_decimal_test_func<Decimal128V3, TYPE_FLOAT>();
from_decimal_test_func<Decimal256, TYPE_FLOAT>();
from_decimal_test_func<Decimal128V2, TYPE_FLOAT>();
from_decimal_test_func<Decimal32, TYPE_DOUBLE>();
from_decimal_test_func<Decimal64, TYPE_DOUBLE>();
from_decimal_test_func<Decimal128V3, TYPE_DOUBLE>();
from_decimal_test_func<Decimal256, TYPE_DOUBLE>();
from_decimal_test_func<Decimal128V2, TYPE_DOUBLE>();
}
TEST_F(FunctionCastToFloatTest, test_from_decimal_overflow) {
from_decimal_overflow_test_func();
}
TEST_F(FunctionCastToFloatTest, test_from_date) {
from_date_test_func<TYPE_FLOAT>();
from_date_test_func<TYPE_DOUBLE>();
}
TEST_F(FunctionCastToFloatTest, test_from_datetime) {
from_datetime_test_func<TYPE_FLOAT, 0>();
from_datetime_test_func<TYPE_FLOAT, 1>();
from_datetime_test_func<TYPE_FLOAT, 3>();
from_datetime_test_func<TYPE_FLOAT, 6>();
from_datetime_test_func<TYPE_DOUBLE, 0>();
from_datetime_test_func<TYPE_DOUBLE, 1>();
from_datetime_test_func<TYPE_DOUBLE, 3>();
from_datetime_test_func<TYPE_DOUBLE, 6>();
}
TEST_F(FunctionCastToFloatTest, test_from_time) {
from_time_test_func<TYPE_FLOAT>();
from_time_test_func<TYPE_DOUBLE>();
}
} // namespace doris::vectorized