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

Reply via email to