[BUG] Fix potential overflow exception when do money format for double (#6408)
* [BUG] Fix potential overflow bug when do money format for double Co-authored-by: caiconghui <caiconghui@xiaomi.com>
This commit is contained in:
@ -879,11 +879,8 @@ StringVal StringFunctions::money_format(FunctionContext* context, const DoubleVa
|
||||
if (v.is_null) {
|
||||
return StringVal::null();
|
||||
}
|
||||
|
||||
double v_cent = MathFunctions::my_double_round(v.val, 2, false, false);
|
||||
bool negative = v_cent < 0;
|
||||
int32_t frac_value = negative ? ((int64_t) (-v_cent * 100)) % 100 : ((int64_t)(v_cent * 100)) % 100;
|
||||
return do_money_format<int64_t, 26>(context, (int64_t) v_cent , frac_value);
|
||||
return do_money_format(context, fmt::format("{:.2f}", v_cent));
|
||||
}
|
||||
|
||||
StringVal StringFunctions::money_format(FunctionContext* context, const DecimalV2Val& v) {
|
||||
@ -893,7 +890,7 @@ StringVal StringFunctions::money_format(FunctionContext* context, const DecimalV
|
||||
|
||||
DecimalV2Value rounded(0);
|
||||
DecimalV2Value::from_decimal_val(v).round(&rounded, 2, HALF_UP);
|
||||
return do_money_format<int64_t, 26>(context, rounded.int_value(), abs(rounded.frac_value()));
|
||||
return do_money_format<int64_t, 26>(context, rounded.int_value(), abs(rounded.frac_value() / 10000000));
|
||||
}
|
||||
|
||||
StringVal StringFunctions::money_format(FunctionContext* context, const BigIntVal& v) {
|
||||
|
||||
@ -162,6 +162,28 @@ public:
|
||||
return result;
|
||||
};
|
||||
|
||||
// Note string value must be valid decimal string which contains two digits after the decimal point
|
||||
static StringVal do_money_format(FunctionContext* context, const string& value) {
|
||||
bool is_positive = (value[0] != '-');
|
||||
int32_t result_len = value.size() + (value.size() - (is_positive ? 4 : 5)) / 3;
|
||||
StringVal result = StringVal::create_temp_string_val(context, result_len);
|
||||
if (!is_positive) {
|
||||
*result.ptr = '-';
|
||||
}
|
||||
for (int i = value.size() - 4, j = result_len - 4; i >= 0; i = i - 3, j = j - 4) {
|
||||
*(result.ptr + j) = *(value.data() + i);
|
||||
if (i - 1 < 0) break;
|
||||
*(result.ptr + j - 1) = *(value.data() + i - 1);
|
||||
if (i - 2 < 0) break;
|
||||
*(result.ptr + j - 2) = *(value.data() + i - 2);
|
||||
if (j - 3 > 1 || (j - 3 == 1 && is_positive)) {
|
||||
*(result.ptr + j - 3) = ',';
|
||||
}
|
||||
}
|
||||
memcpy(result.ptr + result_len - 3, value.data() + value.size() - 3, 3);
|
||||
return result;
|
||||
};
|
||||
|
||||
static StringVal split_part(FunctionContext* context, const StringVal& content,
|
||||
const StringVal& delimiter, const IntVal& field);
|
||||
|
||||
|
||||
@ -47,7 +47,7 @@ private:
|
||||
TEST_F(StringFunctionsTest, do_money_format_for_bigint_bench) {
|
||||
doris_udf::FunctionContext* context = new doris_udf::FunctionContext();
|
||||
StringVal expected =
|
||||
AnyValUtil::from_string_temp(context, std::string("9,223,372,036,854,775,807.00"));
|
||||
AnyValUtil::from_string(ctx, std::string("9,223,372,036,854,775,807.00"));
|
||||
BigIntVal bigIntVal(9223372036854775807);
|
||||
for (int i = 0; i < LOOP_LESS_OR_MORE(10, 10000000); i++) {
|
||||
StringVal result = StringFunctions::money_format(context, bigIntVal);
|
||||
@ -58,7 +58,7 @@ TEST_F(StringFunctionsTest, do_money_format_for_bigint_bench) {
|
||||
|
||||
TEST_F(StringFunctionsTest, do_money_format_for_decimalv2_bench) {
|
||||
doris_udf::FunctionContext* context = new doris_udf::FunctionContext();
|
||||
StringVal expected = AnyValUtil::from_string_temp(context, std::string("9,223,372,085.85"));
|
||||
StringVal expected = AnyValUtil::from_string(ctx, std::string("9,223,372,085.87"));
|
||||
DecimalV2Value dv1(std::string("9223372085.8678"));
|
||||
DecimalV2Val decimalV2Val;
|
||||
dv1.to_decimal_val(&decimalV2Val);
|
||||
@ -73,15 +73,15 @@ TEST_F(StringFunctionsTest, money_format_bigint) {
|
||||
doris_udf::FunctionContext* context = new doris_udf::FunctionContext();
|
||||
|
||||
StringVal result = StringFunctions::money_format(context, doris_udf::BigIntVal(123456));
|
||||
StringVal expected = AnyValUtil::from_string_temp(context, std::string("123,456.00"));
|
||||
StringVal expected = AnyValUtil::from_string(ctx, std::string("123,456.00"));
|
||||
ASSERT_EQ(expected, result);
|
||||
|
||||
result = StringFunctions::money_format(context, doris_udf::BigIntVal(-123456));
|
||||
expected = AnyValUtil::from_string_temp(context, std::string("-123,456.00"));
|
||||
expected = AnyValUtil::from_string(ctx, std::string("-123,456.00"));
|
||||
ASSERT_EQ(expected, result);
|
||||
|
||||
result = StringFunctions::money_format(context, doris_udf::BigIntVal(9223372036854775807));
|
||||
expected = AnyValUtil::from_string_temp(context, std::string("9,223,372,036,854,775,807.00"));
|
||||
expected = AnyValUtil::from_string(ctx, std::string("9,223,372,036,854,775,807.00"));
|
||||
ASSERT_EQ(expected, result);
|
||||
delete context;
|
||||
}
|
||||
@ -106,20 +106,25 @@ TEST_F(StringFunctionsTest, money_format_double) {
|
||||
doris_udf::FunctionContext* context = new doris_udf::FunctionContext();
|
||||
|
||||
StringVal result = StringFunctions::money_format(context, doris_udf::DoubleVal(1234.456));
|
||||
StringVal expected = AnyValUtil::from_string_temp(context, std::string("1,234.46"));
|
||||
StringVal expected = AnyValUtil::from_string(ctx, std::string("1,234.46"));
|
||||
ASSERT_EQ(expected, result);
|
||||
|
||||
result = StringFunctions::money_format(context, doris_udf::DoubleVal(1234.45));
|
||||
expected = AnyValUtil::from_string_temp(context, std::string("1,234.45"));
|
||||
expected = AnyValUtil::from_string(ctx, std::string("1,234.45"));
|
||||
ASSERT_EQ(expected, result);
|
||||
|
||||
result = StringFunctions::money_format(context, doris_udf::DoubleVal(1234.4));
|
||||
expected = AnyValUtil::from_string_temp(context, std::string("1,234.40"));
|
||||
expected = AnyValUtil::from_string(ctx, std::string("1,234.40"));
|
||||
ASSERT_EQ(expected, result);
|
||||
|
||||
result = StringFunctions::money_format(context, doris_udf::DoubleVal(1234.454));
|
||||
expected = AnyValUtil::from_string_temp(context, std::string("1,234.45"));
|
||||
expected = AnyValUtil::from_string(ctx, std::string("1,234.45"));
|
||||
ASSERT_EQ(expected, result);
|
||||
|
||||
result = StringFunctions::money_format(context, doris_udf::DoubleVal(-36854775807.039));
|
||||
expected = AnyValUtil::from_string(ctx, std::string("-36,854,775,807.04"));
|
||||
ASSERT_EQ(expected, result);
|
||||
|
||||
delete context;
|
||||
}
|
||||
|
||||
@ -131,7 +136,7 @@ TEST_F(StringFunctionsTest, money_format_decimal_v2) {
|
||||
dv1.to_decimal_val(&value1);
|
||||
|
||||
StringVal result = StringFunctions::money_format(context, value1);
|
||||
StringVal expected = AnyValUtil::from_string_temp(context, std::string("3,333,333,333.22"));
|
||||
StringVal expected = AnyValUtil::from_string(ctx, std::string("3,333,333,333.22"));
|
||||
ASSERT_EQ(expected, result);
|
||||
|
||||
DecimalV2Value dv2(std::string("-740740740.71604938271975308642"));
|
||||
@ -139,7 +144,7 @@ TEST_F(StringFunctionsTest, money_format_decimal_v2) {
|
||||
dv2.to_decimal_val(&value2);
|
||||
|
||||
result = StringFunctions::money_format(context, value2);
|
||||
expected = AnyValUtil::from_string_temp(context, std::string("-740,740,740.72"));
|
||||
expected = AnyValUtil::from_string(ctx, std::string("-740,740,740.72"));
|
||||
ASSERT_EQ(expected, result);
|
||||
delete context;
|
||||
}
|
||||
@ -147,38 +152,38 @@ TEST_F(StringFunctionsTest, money_format_decimal_v2) {
|
||||
TEST_F(StringFunctionsTest, split_part) {
|
||||
doris_udf::FunctionContext* context = new doris_udf::FunctionContext();
|
||||
|
||||
ASSERT_EQ(AnyValUtil::from_string_temp(context, std::string("hello")),
|
||||
ASSERT_EQ(AnyValUtil::from_string(ctx, std::string("hello")),
|
||||
StringFunctions::split_part(context, StringVal("hello word"), StringVal(" "), 1));
|
||||
|
||||
ASSERT_EQ(AnyValUtil::from_string_temp(context, std::string("word")),
|
||||
ASSERT_EQ(AnyValUtil::from_string(ctx, std::string("word")),
|
||||
StringFunctions::split_part(context, StringVal("hello word"), StringVal(" "), 2));
|
||||
|
||||
ASSERT_EQ(StringVal::null(),
|
||||
StringFunctions::split_part(context, StringVal("hello word"), StringVal(" "), 3));
|
||||
|
||||
ASSERT_EQ(AnyValUtil::from_string_temp(context, std::string("")),
|
||||
ASSERT_EQ(AnyValUtil::from_string(ctx, std::string("")),
|
||||
StringFunctions::split_part(context, StringVal("hello word"), StringVal("hello"), 1));
|
||||
|
||||
ASSERT_EQ(AnyValUtil::from_string_temp(context, std::string(" word")),
|
||||
ASSERT_EQ(AnyValUtil::from_string(ctx, std::string(" word")),
|
||||
StringFunctions::split_part(context, StringVal("hello word"), StringVal("hello"), 2));
|
||||
|
||||
ASSERT_EQ(AnyValUtil::from_string_temp(context, std::string("2019年9")),
|
||||
ASSERT_EQ(AnyValUtil::from_string(ctx, std::string("2019年9")),
|
||||
StringFunctions::split_part(context, StringVal("2019年9月8日"), StringVal("月"), 1));
|
||||
|
||||
ASSERT_EQ(AnyValUtil::from_string_temp(context, std::string("")),
|
||||
ASSERT_EQ(AnyValUtil::from_string(ctx, std::string("")),
|
||||
StringFunctions::split_part(context, StringVal("abcdabda"), StringVal("a"), 1));
|
||||
|
||||
ASSERT_EQ(AnyValUtil::from_string_temp(context, std::string("bcd")),
|
||||
ASSERT_EQ(AnyValUtil::from_string(ctx, std::string("bcd")),
|
||||
StringFunctions::split_part(context, StringVal("abcdabda"), StringVal("a"), 2));
|
||||
|
||||
ASSERT_EQ(AnyValUtil::from_string_temp(context, std::string("bd")),
|
||||
ASSERT_EQ(AnyValUtil::from_string(ctx, std::string("bd")),
|
||||
StringFunctions::split_part(context, StringVal("abcdabda"), StringVal("a"), 3));
|
||||
|
||||
ASSERT_EQ(AnyValUtil::from_string_temp(context, std::string("")),
|
||||
ASSERT_EQ(AnyValUtil::from_string(ctx, std::string("")),
|
||||
StringFunctions::split_part(context, StringVal("abcdabda"), StringVal("a"), 4));
|
||||
|
||||
ASSERT_EQ(
|
||||
AnyValUtil::from_string_temp(context, std::string("#123")),
|
||||
AnyValUtil::from_string(ctx, std::string("#123")),
|
||||
StringFunctions::split_part(context, StringVal("abc###123###234"), StringVal("##"), 2));
|
||||
|
||||
delete context;
|
||||
@ -285,36 +290,36 @@ TEST_F(StringFunctionsTest, null_or_empty) {
|
||||
TEST_F(StringFunctionsTest, substring) {
|
||||
doris_udf::FunctionContext* context = new doris_udf::FunctionContext();
|
||||
|
||||
ASSERT_EQ(AnyValUtil::from_string_temp(context, std::string("")),
|
||||
ASSERT_EQ(AnyValUtil::from_string(ctx, std::string("")),
|
||||
StringFunctions::substring(context, StringVal("hello word"), 0, 5));
|
||||
|
||||
ASSERT_EQ(AnyValUtil::from_string_temp(context, std::string("hello")),
|
||||
ASSERT_EQ(AnyValUtil::from_string(ctx, std::string("hello")),
|
||||
StringFunctions::substring(context, StringVal("hello word"), 1, 5));
|
||||
|
||||
ASSERT_EQ(AnyValUtil::from_string_temp(context, std::string("word")),
|
||||
ASSERT_EQ(AnyValUtil::from_string(ctx, std::string("word")),
|
||||
StringFunctions::substring(context, StringVal("hello word"), 7, 4));
|
||||
|
||||
ASSERT_EQ(StringVal::null(), StringFunctions::substring(context, StringVal::null(), 1, 0));
|
||||
|
||||
ASSERT_EQ(AnyValUtil::from_string_temp(context, std::string("")),
|
||||
ASSERT_EQ(AnyValUtil::from_string(ctx, std::string("")),
|
||||
StringFunctions::substring(context, StringVal("hello word"), 1, 0));
|
||||
|
||||
ASSERT_EQ(AnyValUtil::from_string_temp(context, std::string(" word")),
|
||||
ASSERT_EQ(AnyValUtil::from_string(ctx, std::string(" word")),
|
||||
StringFunctions::substring(context, StringVal("hello word"), -5, 5));
|
||||
|
||||
ASSERT_EQ(AnyValUtil::from_string_temp(context, std::string("hello word 你")),
|
||||
ASSERT_EQ(AnyValUtil::from_string(ctx, std::string("hello word 你")),
|
||||
StringFunctions::substring(context, StringVal("hello word 你好"), 1, 12));
|
||||
|
||||
ASSERT_EQ(AnyValUtil::from_string_temp(context, std::string("好")),
|
||||
ASSERT_EQ(AnyValUtil::from_string(ctx, std::string("好")),
|
||||
StringFunctions::substring(context, StringVal("hello word 你好"), 13, 1));
|
||||
|
||||
ASSERT_EQ(AnyValUtil::from_string_temp(context, std::string("")),
|
||||
ASSERT_EQ(AnyValUtil::from_string(ctx, std::string("")),
|
||||
StringFunctions::substring(context, StringVal("hello word 你好"), 1, 0));
|
||||
|
||||
ASSERT_EQ(AnyValUtil::from_string_temp(context, std::string("rd 你好")),
|
||||
ASSERT_EQ(AnyValUtil::from_string(ctx, std::string("rd 你好")),
|
||||
StringFunctions::substring(context, StringVal("hello word 你好"), -5, 5));
|
||||
|
||||
ASSERT_EQ(AnyValUtil::from_string_temp(context, std::string("h")),
|
||||
ASSERT_EQ(AnyValUtil::from_string(ctx, std::string("h")),
|
||||
StringFunctions::substring(context, StringVal("hello word 你好"), 1, 1));
|
||||
delete context;
|
||||
}
|
||||
@ -323,14 +328,14 @@ TEST_F(StringFunctionsTest, reverse) {
|
||||
FunctionUtils fu;
|
||||
doris_udf::FunctionContext* context = fu.get_fn_ctx();
|
||||
|
||||
ASSERT_EQ(AnyValUtil::from_string_temp(context, std::string("olleh")),
|
||||
ASSERT_EQ(AnyValUtil::from_string(ctx, std::string("olleh")),
|
||||
StringFunctions::reverse(context, StringVal("hello")));
|
||||
ASSERT_EQ(StringVal::null(), StringFunctions::reverse(context, StringVal::null()));
|
||||
|
||||
ASSERT_EQ(AnyValUtil::from_string_temp(context, std::string("")),
|
||||
ASSERT_EQ(AnyValUtil::from_string(ctx, std::string("")),
|
||||
StringFunctions::reverse(context, StringVal("")));
|
||||
|
||||
ASSERT_EQ(AnyValUtil::from_string_temp(context, std::string("好你olleh")),
|
||||
ASSERT_EQ(AnyValUtil::from_string(ctx, std::string("好你olleh")),
|
||||
StringFunctions::reverse(context, StringVal("hello你好")));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user