diff --git a/expression/builtin_string.go b/expression/builtin_string.go index 7f5d58aae79c..8df3bbba0109 100644 --- a/expression/builtin_string.go +++ b/expression/builtin_string.go @@ -2969,10 +2969,66 @@ func evalNumDecArgsForFormat(f builtinFunc, row chunk.Row) (string, string, bool } else if d > formatMaxDecimals { d = formatMaxDecimals } + xStr = roundFormatArgs(xStr, int(d)) dStr := strconv.FormatInt(d, 10) return xStr, dStr, false, nil } +func roundFormatArgs(xStr string, maxNumDecimals int) string { + if !strings.Contains(xStr, ".") { + return xStr + } + + sign := false + // xStr cannot have '+' prefix now. + // It is built in `evalNumDecArgsFormat` after evaluating `Evalxxx` method. + if strings.HasPrefix(xStr, "-") { + xStr = strings.Trim(xStr, "-") + sign = true + } + + xArr := strings.Split(xStr, ".") + integerPart := xArr[0] + decimalPart := xArr[1] + + if len(decimalPart) > maxNumDecimals { + t := []byte(decimalPart) + carry := false + if t[maxNumDecimals] >= '5' { + carry = true + } + for i := maxNumDecimals - 1; i >= 0 && carry; i-- { + if t[i] == '9' { + t[i] = '0' + } else { + t[i] = t[i] + 1 + carry = false + } + } + decimalPart = string(t) + t = []byte(integerPart) + for i := len(integerPart) - 1; i >= 0 && carry; i-- { + if t[i] == '9' { + t[i] = '0' + } else { + t[i] = t[i] + 1 + carry = false + } + } + if carry { + integerPart = "1" + string(t) + } else { + integerPart = string(t) + } + } + + xStr = integerPart + "." + decimalPart + if sign { + xStr = "-" + xStr + } + return xStr +} + type builtinFormatWithLocaleSig struct { baseBuiltinFunc } diff --git a/expression/builtin_string_test.go b/expression/builtin_string_test.go index 5de8bcdbf5e2..d2015df5cd9e 100644 --- a/expression/builtin_string_test.go +++ b/expression/builtin_string_test.go @@ -1608,6 +1608,13 @@ func (s *testEvaluatorSuite) TestFormat(c *C) { ret interface{} warnings int }{ + // issue #8796 + {1.12345, 4, "1.1235", 0}, + {9.99999, 4, "10.0000", 0}, + {1.99999, 4, "2.0000", 0}, + {1.09999, 4, "1.1000", 0}, + {-2.5000, 0, "-3", 0}, + {12332.123444, 4, "12,332.1234", 0}, {12332.123444, 0, "12,332", 0}, {12332.123444, -4, "12,332", 0},