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 <[email protected]>
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 <[email protected]>
---
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: [email protected]
For additional commands, e-mail: [email protected]