This is an automated email from the ASF dual-hosted git repository. caiconghui pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/incubator-doris.git
The following commit(s) were added to refs/heads/master by this push: new 285d44c [BUG] Fix potential overflow exception when do money format for double (#6408) 285d44c is described below commit 285d44cd48bd2957e3b7f09a70e8ead00d1ff80f Author: caiconghui <55968745+caicong...@users.noreply.github.com> AuthorDate: Sun Aug 15 18:40:26 2021 +0800 [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 <caicong...@xiaomi.com> --- be/src/exprs/string_functions.cpp | 7 +--- be/src/exprs/string_functions.h | 22 ++++++++++ be/test/exprs/string_functions_test.cpp | 73 ++++++++++++++++++--------------- 3 files changed, 63 insertions(+), 39 deletions(-) diff --git a/be/src/exprs/string_functions.cpp b/be/src/exprs/string_functions.cpp index 8822065..69d1898 100644 --- a/be/src/exprs/string_functions.cpp +++ b/be/src/exprs/string_functions.cpp @@ -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) { diff --git a/be/src/exprs/string_functions.h b/be/src/exprs/string_functions.h index dbd8cee..65b5418 100644 --- a/be/src/exprs/string_functions.h +++ b/be/src/exprs/string_functions.h @@ -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); diff --git a/be/test/exprs/string_functions_test.cpp b/be/test/exprs/string_functions_test.cpp index 99532b6..e7bae96 100644 --- a/be/test/exprs/string_functions_test.cpp +++ b/be/test/exprs/string_functions_test.cpp @@ -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你好"))); } --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org For additional commands, e-mail: commits-h...@doris.apache.org