This is an automated email from the ASF dual-hosted git repository.

jacktengg pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/master by this push:
     new 665fd30ce30 [fix](be) Fix CONV results for negative string inputs 
(#68984)
665fd30ce30 is described below

commit 665fd30ce300787679ef6c3cb00a94c2fc37b141
Author: TengJianPing <[email protected]>
AuthorDate: Tue Oct 13 17:50:52 2026 +0800

    [fix](be) Fix CONV results for negative string inputs (#68984)
    
    ### What problem does this PR solve?
    
    Issue Number: N/A
    
    Related PR: N/A
    
    Problem Summary: CONV('-10', 10, 10) returned 18446744073709551615 while
    CONV(-10, 10, 10) returned 18446744073709551606. Converting the string
    to
    signed output with CONV('-10', 10, -10) or CONV('-10', 2, -10) likewise
    returned -1 instead of -10 or -2.
    
    The base-aware string parser added one to UINT64_MAX when it encountered
    a negative sign, wrapping the unsigned magnitude limit to zero and
    incorrectly reporting overflow. Expand the negative magnitude limit only
    for signed integer types, using unsigned arithmetic; keep the full
    unsigned magnitude limit when parsing negative strings as uint64_t.
    
    Negative destination bases continue to select signed output, and allowed
    base magnitudes remain [2, 36]. Add unsigned parser boundary tests and
    CONV
    coverage for negative string and integer inputs, signed and unsigned
    output, 64-bit limits and overflow, NULLs, all TINYINT base values, all
    eight constant/column argument combinations, and constant folding.
    Generate the regression output through the standard regression script.
    
    The reported six-expression query now returns
    18446744073709551606, 18446744073709551606, -10, -10, -2, -2.
    
    ### Release note
    
    Fix incorrect CONV results for negative string inputs, including signed
    output selected by a negative destination base.
    
    ### Check List (For Author)
    
    - Test:
        - ASAN BE build: ./build.sh --be -j32
    - Unit Test: ./run-be-ut.sh --run
    --filter='MathFunctionTest.conv*:StringToIntWithBase.*' -j32 (10 tests
    passed)
    - Regression test: ./run-regression-test.sh --run -d
    query_p0/sql_functions/math_functions -s test_conv_negative_base_range
    -forceGenOut
    - Regression test: ./run-regression-test.sh --run -d
    query_p0/sql_functions/math_functions -s
    test_conv,test_conv_negative_base_range (2 suites passed)
    - Manual test: verified the reported six-expression SQL on the rebuilt
    worktree cluster
    - clang-format 16, clang-tidy on changed lines, build hygiene, and git
    diff checks passed
    - Behavior changed: Yes, correct negative string conversion results
    while preserving existing negative base support
    - Does this need documentation: No, this is a bug fix with existing base
    semantics preserved
    ### Check List (For Reviewer who merge this PR)
    
    - [ ] Confirm the release note
    - [ ] Confirm test cases
    - [ ] Confirm document
    - [ ] Add branch pick label <!-- Add branch pick label that this PR
    should merge into -->
---
 be/src/exprs/function/function_conv.cpp            |  10 +-
 be/src/util/string_parser.hpp                      |   7 +-
 be/test/exprs/function/function_math_test.cpp      | 119 +++++++++
 be/test/util/string_parser_test.cpp                |  81 +++++-
 .../test_conv_negative_base_range.out              | 295 +++++++++++++++++++++
 .../test_conv_negative_base_range.groovy           | 135 ++++++++++
 6 files changed, 639 insertions(+), 8 deletions(-)

diff --git a/be/src/exprs/function/function_conv.cpp 
b/be/src/exprs/function/function_conv.cpp
index 1c4552f1d3b..6bb16a981da 100644
--- a/be/src/exprs/function/function_conv.cpp
+++ b/be/src/exprs/function/function_conv.cpp
@@ -168,8 +168,9 @@ struct ConvInt64Impl {
         }
 
         int64_t decimal_num = num;
-        if (src_base != 10) {
-            if (!MathFunctions::decimal_in_base_to_decimal(num, src_base, 
&decimal_num)) {
+        const auto src_radix = static_cast<Int8>(std::abs(src_base));
+        if (src_radix != 10) {
+            if (!MathFunctions::decimal_in_base_to_decimal(num, src_radix, 
&decimal_num)) {
                 MathFunctions::handle_parse_result(dst_base, &decimal_num,
                                                    
StringParser::PARSE_OVERFLOW);
             }
@@ -199,8 +200,9 @@ struct ConvStringImpl {
         // if 'ffffffffffffff' parse as int64_t will be overflow, will be get 
max value: std::numeric_limits<int64_t>::max()
         // so change it parse as uint64_t, and return value could still use 
int64_t, in function decimal_to_base could handle it.
         // But if the value is still overflow in uint64_t, will get max value 
of uint64_t
-        int64_t decimal_num =
-                StringParser::string_to_int<uint64_t>(str.data, new_size, 
src_base, &parse_res);
+        // The sign of src_base controls input validation; parsing uses its 
magnitude.
+        int64_t decimal_num = StringParser::string_to_int<uint64_t>(str.data, 
new_size,
+                                                                    
std::abs(src_base), &parse_res);
         if (src_base < 0 && decimal_num >= 0) {
             result_null_map[index] = true;
             result_column->insert_default();
diff --git a/be/src/util/string_parser.hpp b/be/src/util/string_parser.hpp
index d2a325cbb88..a3ae5532137 100644
--- a/be/src/util/string_parser.hpp
+++ b/be/src/util/string_parser.hpp
@@ -488,7 +488,8 @@ T StringParser::string_to_int_internal(const char* 
__restrict s, int len, ParseR
     switch (*s) {
     case '-':
         negative = true;
-        max_val += 1;
+        // Only signed types have an extra value in their negative range.
+        max_val += std::numeric_limits<T>::is_signed;
         [[fallthrough]];
     case '+':
         ++i;
@@ -611,7 +612,9 @@ T StringParser::string_to_int_internal(const char* 
__restrict s, int64_t len, in
     switch (*s) {
     case '-':
         negative = true;
-        max_val = StringParser::numeric_limits<T>(false) + 1;
+        // Only signed types have an extra value in their negative range.
+        // Keep the unsigned magnitude limit unchanged to avoid wrapping it to 
zero.
+        max_val += std::numeric_limits<T>::is_signed;
         [[fallthrough]];
     case '+':
         i = 1;
diff --git a/be/test/exprs/function/function_math_test.cpp 
b/be/test/exprs/function/function_math_test.cpp
index 2e2196f226e..cdf4346cfa1 100644
--- a/be/test/exprs/function/function_math_test.cpp
+++ b/be/test/exprs/function/function_math_test.cpp
@@ -823,21 +823,140 @@ TEST(MathFunctionTest, conv_int64_boundary_test) {
              VARCHAR("-9223372036854775808")},
             {{BIGINT(8000000000000000LL), TINYINT(16), TINYINT(10)},
              VARCHAR("9223372036854775808")},
+            {{BIGINT(std::numeric_limits<int64_t>::min()), TINYINT(10), 
TINYINT(10)},
+             VARCHAR("9223372036854775808")},
             {{BIGINT(std::numeric_limits<int64_t>::min()), TINYINT(10), 
TINYINT(-10)},
              VARCHAR("-9223372036854775808")},
             {{BIGINT(8000000000000000LL), TINYINT(16), TINYINT(-16)}, 
VARCHAR("-8000000000000000")},
             {{BIGINT(10000000000000000LL), TINYINT(16), TINYINT(-10)}, 
VARCHAR("-1")},
             {{BIGINT(10000000000000000LL), TINYINT(16), TINYINT(10)},
              VARCHAR("18446744073709551615")},
+            {{BIGINT(-10), TINYINT(10), TINYINT(10)}, 
VARCHAR("18446744073709551606")},
+            {{BIGINT(-10), TINYINT(2), TINYINT(10)}, 
VARCHAR("18446744073709551614")},
+            {{BIGINT(-10), TINYINT(10), TINYINT(-10)}, VARCHAR("-10")},
+            {{BIGINT(-10), TINYINT(2), TINYINT(-10)}, VARCHAR("-2")},
             {{BIGINT(-255), TINYINT(10), TINYINT(-16)}, VARCHAR("-FF")},
             {{BIGINT(-1), TINYINT(10), TINYINT(16)}, 
VARCHAR("FFFFFFFFFFFFFFFF")},
+            {{BIGINT(255), TINYINT(10), TINYINT(16)}, VARCHAR("FF")},
             {{BIGINT(255), TINYINT(10), TINYINT(-16)}, VARCHAR("FF")},
+            {{BIGINT(0), TINYINT(16), TINYINT(10)}, VARCHAR("0")},
             {{BIGINT(0), TINYINT(16), TINYINT(-10)}, VARCHAR("0")},
+            {{Null(), TINYINT(16), TINYINT(10)}, Null()},
             {{Null(), TINYINT(16), TINYINT(-10)}, Null()},
     };
     check_function_all_arg_comb<DataTypeString, true>("conv", input_types, 
data_set);
 }
 
+TEST(MathFunctionTest, conv_string_boundary_test) {
+    InputTypeSet input_types = {PrimitiveType::TYPE_VARCHAR, 
PrimitiveType::TYPE_TINYINT,
+                                PrimitiveType::TYPE_TINYINT};
+    DataSet data_set = {
+            {{VARCHAR("-10"), TINYINT(10), TINYINT(10)}, 
VARCHAR("18446744073709551606")},
+            {{VARCHAR("-10"), TINYINT(2), TINYINT(10)}, 
VARCHAR("18446744073709551614")},
+            {{VARCHAR("-10"), TINYINT(10), TINYINT(-10)}, VARCHAR("-10")},
+            {{VARCHAR("-10"), TINYINT(2), TINYINT(-10)}, VARCHAR("-2")},
+            {{VARCHAR("-ff"), TINYINT(16), TINYINT(-16)}, VARCHAR("-FF")},
+            {{VARCHAR("  -10  "), TINYINT(10), TINYINT(10)}, 
VARCHAR("18446744073709551606")},
+            {{VARCHAR("-10.5"), TINYINT(10), TINYINT(10)}, 
VARCHAR("18446744073709551606")},
+            {{VARCHAR("-0"), TINYINT(10), TINYINT(10)}, VARCHAR("0")},
+            {{VARCHAR("-100"), TINYINT(10), TINYINT(16)}, 
VARCHAR("FFFFFFFFFFFFFF9C")},
+            {{VARCHAR("-ff"), TINYINT(16), TINYINT(10)}, 
VARCHAR("18446744073709551361")},
+            {{VARCHAR("-9223372036854775808"), TINYINT(10), TINYINT(10)},
+             VARCHAR("9223372036854775808")},
+            {{VARCHAR("-9223372036854775808"), TINYINT(10), TINYINT(-10)},
+             VARCHAR("-9223372036854775808")},
+            {{VARCHAR("-9223372036854775809"), TINYINT(10), TINYINT(10)},
+             VARCHAR("9223372036854775807")},
+            {{VARCHAR("18446744073709551615"), TINYINT(10), TINYINT(16)},
+             VARCHAR("FFFFFFFFFFFFFFFF")},
+            {{VARCHAR("18446744073709551615"), TINYINT(10), TINYINT(-10)}, 
VARCHAR("-1")},
+            {{VARCHAR("-18446744073709551615"), TINYINT(10), TINYINT(10)}, 
VARCHAR("1")},
+            {{VARCHAR("18446744073709551616"), TINYINT(10), TINYINT(10)},
+             VARCHAR("18446744073709551615")},
+            {{VARCHAR("-18446744073709551616"), TINYINT(10), TINYINT(10)},
+             VARCHAR("18446744073709551615")},
+            {{VARCHAR("18446744073709551616"), TINYINT(10), TINYINT(-10)}, 
VARCHAR("-1")},
+            {{VARCHAR("-18446744073709551616"), TINYINT(10), TINYINT(-10)}, 
VARCHAR("-1")},
+            {{VARCHAR(""), TINYINT(10), TINYINT(10)}, VARCHAR("0")},
+            {{VARCHAR("-+10"), TINYINT(10), TINYINT(10)}, VARCHAR("0")},
+            {{Null(), TINYINT(10), TINYINT(10)}, Null()},
+    };
+    check_function_all_arg_comb<DataTypeString, true>("conv", input_types, 
data_set);
+}
+
+TEST(MathFunctionTest, conv_negative_source_base_test) {
+    InputTypeSet int_input_types = {PrimitiveType::TYPE_BIGINT, 
PrimitiveType::TYPE_TINYINT,
+                                    PrimitiveType::TYPE_TINYINT};
+    DataSet int_data_set = {
+            {{BIGINT(-121), TINYINT(-2), TINYINT(-10)}, VARCHAR("-1")},
+            {{BIGINT(-121), TINYINT(-2), TINYINT(10)}, 
VARCHAR("18446744073709551615")},
+            {{BIGINT(-1012), TINYINT(-2), TINYINT(-10)}, VARCHAR("-5")},
+            {{BIGINT(-10), TINYINT(-2), TINYINT(-10)}, VARCHAR("-2")},
+            {{BIGINT(-10), TINYINT(-10), TINYINT(-10)}, VARCHAR("-10")},
+            {{BIGINT(-10), TINYINT(-36), TINYINT(-10)}, VARCHAR("-36")},
+            {{BIGINT(std::numeric_limits<int64_t>::min()), TINYINT(-10), 
TINYINT(-10)},
+             VARCHAR("-9223372036854775808")},
+            {{BIGINT(-10000000000000000LL), TINYINT(-16), TINYINT(-10)}, 
VARCHAR("-1")},
+            {{BIGINT(10), TINYINT(-10), TINYINT(-10)}, Null()},
+            {{BIGINT(0), TINYINT(-2), TINYINT(-10)}, Null()},
+            {{Null(), TINYINT(-2), TINYINT(-10)}, Null()},
+    };
+    check_function_all_arg_comb<DataTypeString, true>("conv", int_input_types, 
int_data_set);
+
+    InputTypeSet string_input_types = {PrimitiveType::TYPE_VARCHAR, 
PrimitiveType::TYPE_TINYINT,
+                                       PrimitiveType::TYPE_TINYINT};
+    DataSet string_data_set = {
+            {{VARCHAR("-121"), TINYINT(-2), TINYINT(-10)}, VARCHAR("-1")},
+            {{VARCHAR("-121"), TINYINT(-2), TINYINT(10)}, 
VARCHAR("18446744073709551615")},
+            {{VARCHAR("-1a1"), TINYINT(-10), TINYINT(-10)}, VARCHAR("-1")},
+            {{VARCHAR("-1a1"), TINYINT(-10), TINYINT(10)}, 
VARCHAR("18446744073709551615")},
+            {{VARCHAR("  -1A1  "), TINYINT(-10), TINYINT(-16)}, VARCHAR("-1")},
+            {{VARCHAR("-1012"), TINYINT(-2), TINYINT(-10)}, VARCHAR("-5")},
+            {{VARCHAR("-123a9"), TINYINT(-10), TINYINT(-10)}, VARCHAR("-123")},
+            {{VARCHAR("-1z1"), TINYINT(-36), TINYINT(-10)}, VARCHAR("-2557")},
+            {{VARCHAR("-10"), TINYINT(-2), TINYINT(-10)}, VARCHAR("-2")},
+            {{VARCHAR("-10"), TINYINT(-10), TINYINT(-10)}, VARCHAR("-10")},
+            {{VARCHAR("-10"), TINYINT(-36), TINYINT(-10)}, VARCHAR("-36")},
+            {{VARCHAR("-9223372036854775808"), TINYINT(-10), TINYINT(-10)},
+             VARCHAR("-9223372036854775808")},
+            {{VARCHAR("-18446744073709551616"), TINYINT(-10), TINYINT(-10)}, 
Null()},
+            {{VARCHAR("10"), TINYINT(-10), TINYINT(-10)}, Null()},
+            {{VARCHAR("-0"), TINYINT(-2), TINYINT(-10)}, Null()},
+            {{Null(), TINYINT(-2), TINYINT(-10)}, Null()},
+    };
+    check_function_all_arg_comb<DataTypeString, true>("conv", 
string_input_types, string_data_set);
+}
+
+TEST(MathFunctionTest, conv_base_range_test) {
+    InputTypeSet int_input_types = {PrimitiveType::TYPE_BIGINT, 
PrimitiveType::TYPE_TINYINT,
+                                    PrimitiveType::TYPE_TINYINT};
+    InputTypeSet string_input_types = {PrimitiveType::TYPE_VARCHAR, 
PrimitiveType::TYPE_TINYINT,
+                                       PrimitiveType::TYPE_TINYINT};
+    DataSet int_data_set;
+    DataSet string_data_set;
+    for (int base = std::numeric_limits<Int8>::min(); base <= 
std::numeric_limits<Int8>::max();
+         ++base) {
+        const int abs_base = std::abs(base);
+        const bool valid_base = abs_base >= 2 && abs_base <= 36;
+        Expect expected = valid_base ? Expect(VARCHAR("10")) : Expect(Null());
+        for (Int64 value : {-10, 0, 10}) {
+            std::string converted = value == 0 ? "0"
+                                               : std::to_string(value < 0 ? 
UInt64 {0} - abs_base
+                                                                          : 
UInt64(abs_base));
+            Expect src_expected = valid_base && (base > 0 || value < 0) ? 
Expect(VARCHAR(converted))
+                                                                        : 
Expect(Null());
+            int_data_set.push_back({{BIGINT(value), TINYINT(base), 
TINYINT(10)}, src_expected});
+            string_data_set.push_back(
+                    {{VARCHAR(std::to_string(value)), TINYINT(base), 
TINYINT(10)}, src_expected});
+        }
+        int_data_set.push_back({{BIGINT(abs_base), TINYINT(10), 
TINYINT(base)}, expected});
+        string_data_set.push_back(
+                {{VARCHAR(std::to_string(abs_base)), TINYINT(10), 
TINYINT(base)}, expected});
+    }
+    check_function_all_arg_comb<DataTypeString, true>("conv", int_input_types, 
int_data_set);
+    check_function_all_arg_comb<DataTypeString, true>("conv", 
string_input_types, string_data_set);
+}
+
 TEST(MathFunctionTest, money_format_test) {
     std::string func_name = "money_format";
 
diff --git a/be/test/util/string_parser_test.cpp 
b/be/test/util/string_parser_test.cpp
index 6101a4cb3e2..2c55abc44bf 100644
--- a/be/test/util/string_parser_test.cpp
+++ b/be/test/util/string_parser_test.cpp
@@ -33,20 +33,53 @@ std::string space[] = {"", "   ", "\t\t\t", "\n\n\n", 
"\v\v\v", "\f\f\f", "\r\r\
 const int space_len = 7;
 
 // Tests conversion of s to integer with and without leading/trailing 
whitespace
-template <typename T>
+template <typename T, bool enable_strict_mode = false>
 void test_int_value(const char* s, T exp_val, StringParser::ParseResult 
exp_result) {
     for (int i = 0; i < space_len; ++i) {
         for (int j = 0; j < space_len; ++j) {
             // All combinations of leading and/or trailing whitespace.
             std::string str = space[i] + s + space[j];
             StringParser::ParseResult result;
-            T val = StringParser::string_to_int<T>(str.data(), str.length(), 
&result);
+            T val = StringParser::string_to_int<T, 
enable_strict_mode>(str.data(), str.length(),
+                                                                       
&result);
             EXPECT_EQ(exp_val, val) << str;
             EXPECT_EQ(result, exp_result);
         }
     }
 }
 
+template <typename T, bool enable_strict_mode>
+void test_unsigned_negative_int_bounds(const char* limit, const char* overflow,
+                                       const char* all_nines) {
+    constexpr T max_value = std::numeric_limits<T>::max();
+    constexpr T negative_ten = max_value - 9;
+    test_int_value<T, enable_strict_mode>("-0", T {0}, 
StringParser::PARSE_SUCCESS);
+    test_int_value<T, enable_strict_mode>("-10", negative_ten, 
StringParser::PARSE_SUCCESS);
+    test_int_value<T, enable_strict_mode>("-00000000000000000010", 
negative_ten,
+                                          StringParser::PARSE_SUCCESS);
+    test_int_value<T, enable_strict_mode>(limit, T {1}, 
StringParser::PARSE_SUCCESS);
+    test_int_value<T, enable_strict_mode>(overflow, T {1}, 
StringParser::PARSE_OVERFLOW);
+    test_int_value<T, enable_strict_mode>(all_nines, T {1}, 
StringParser::PARSE_OVERFLOW);
+    test_int_value<T, enable_strict_mode>(limit + 1, max_value, 
StringParser::PARSE_SUCCESS);
+    test_int_value<T, enable_strict_mode>(overflow + 1, max_value, 
StringParser::PARSE_OVERFLOW);
+    test_int_value<T, enable_strict_mode>(
+            "-10.5", enable_strict_mode ? T {0} : negative_ten,
+            enable_strict_mode ? StringParser::PARSE_FAILURE : 
StringParser::PARSE_SUCCESS);
+}
+
+template <bool enable_strict_mode>
+void test_unsigned_negative_int_bounds() {
+    test_unsigned_negative_int_bounds<uint8_t, enable_strict_mode>("-255", 
"-256", "-999");
+    test_unsigned_negative_int_bounds<uint16_t, enable_strict_mode>("-65535", 
"-65536", "-99999");
+    test_unsigned_negative_int_bounds<uint32_t, 
enable_strict_mode>("-4294967295", "-4294967296",
+                                                                    
"-9999999999");
+    test_unsigned_negative_int_bounds<uint64_t, enable_strict_mode>(
+            "-18446744073709551615", "-18446744073709551616", 
"-99999999999999999999");
+    test_unsigned_negative_int_bounds<uint128_t, enable_strict_mode>(
+            "-340282366920938463463374607431768211455", 
"-340282366920938463463374607431768211456",
+            "-999999999999999999999999999999999999999");
+}
+
 // Tests conversion of s to integer with and without leading/trailing 
whitespace
 template <typename T>
 void test_unsigned_int_value(const char* s, T exp_val, 
StringParser::ParseResult exp_result) {
@@ -226,6 +259,29 @@ TEST(StringToInt, Limit) {
                             StringParser::PARSE_SUCCESS);
 }
 
+TEST(StringToInt, UnsignedNegativeBounds) {
+    test_unsigned_negative_int_bounds<false>();
+}
+
+TEST(StringToInt, UnsignedNegativeBoundsStrict) {
+    test_unsigned_negative_int_bounds<true>();
+}
+
+TEST(StringToInt, SignedLimitsStrict) {
+    test_int_value<int8_t, true>("127", 127, StringParser::PARSE_SUCCESS);
+    test_int_value<int8_t, true>("-128", -128, StringParser::PARSE_SUCCESS);
+    test_int_value<int8_t, true>("-129", -128, StringParser::PARSE_OVERFLOW);
+    test_int_value<int64_t, true>("9223372036854775807", 
std::numeric_limits<int64_t>::max(),
+                                  StringParser::PARSE_SUCCESS);
+    test_int_value<int64_t, true>("-9223372036854775808", 
std::numeric_limits<int64_t>::min(),
+                                  StringParser::PARSE_SUCCESS);
+    test_int_value<int64_t, true>("-9223372036854775809", 
std::numeric_limits<int64_t>::min(),
+                                  StringParser::PARSE_OVERFLOW);
+    test_int_value<int128_t, true>("-170141183460469231731687303715884105728",
+                                   std::numeric_limits<int128_t>::min(),
+                                   StringParser::PARSE_SUCCESS);
+}
+
 TEST(StringToUnsignedInt, Basic) {
     test_unsigned_int_value<uint8_t>("123", 123, StringParser::PARSE_SUCCESS);
     test_unsigned_int_value<uint16_t>("123", 123, StringParser::PARSE_SUCCESS);
@@ -385,6 +441,27 @@ TEST(StringToIntWithBase, Overflow) {
                             StringParser::PARSE_OVERFLOW);
 }
 
+TEST(StringToIntWithBase, UnsignedNegative) {
+    test_int_value<uint8_t>("-10", 10, 246, StringParser::PARSE_SUCCESS);
+    test_int_value<uint8_t>("-255", 10, 1, StringParser::PARSE_SUCCESS);
+    test_int_value<uint8_t>("-256", 10, 1, StringParser::PARSE_OVERFLOW);
+    test_int_value<uint64_t>("-0", 10, 0, StringParser::PARSE_SUCCESS);
+    test_int_value<uint64_t>("-10", 10, 18446744073709551606ULL, 
StringParser::PARSE_SUCCESS);
+    test_int_value<uint64_t>("-10", 2, 18446744073709551614ULL, 
StringParser::PARSE_SUCCESS);
+    test_int_value<uint64_t>("-121", 2, 18446744073709551615ULL, 
StringParser::PARSE_SUCCESS);
+    test_int_value<uint64_t>("-1a1", 10, 18446744073709551615ULL, 
StringParser::PARSE_SUCCESS);
+    test_int_value<uint64_t>("-100", 10, 18446744073709551516ULL, 
StringParser::PARSE_SUCCESS);
+    test_int_value<uint64_t>("-ff", 16, 18446744073709551361ULL, 
StringParser::PARSE_SUCCESS);
+    test_int_value<uint64_t>("-8000000000000000", 16, 9223372036854775808ULL,
+                             StringParser::PARSE_SUCCESS);
+    test_int_value<uint64_t>("-9223372036854775809", 10, 
9223372036854775807ULL,
+                             StringParser::PARSE_SUCCESS);
+    test_int_value<uint64_t>("18446744073709551615", 10, 
18446744073709551615ULL,
+                             StringParser::PARSE_SUCCESS);
+    test_int_value<uint64_t>("-18446744073709551615", 10, 1, 
StringParser::PARSE_SUCCESS);
+    test_int_value<uint64_t>("-18446744073709551616", 10, 1, 
StringParser::PARSE_OVERFLOW);
+}
+
 TEST(StringToIntWithBase, Int8_Exhaustive) {
     char buffer[5];
     for (int i = -256; i <= 256; ++i) {
diff --git 
a/regression-test/data/query_p0/sql_functions/math_functions/test_conv_negative_base_range.out
 
b/regression-test/data/query_p0/sql_functions/math_functions/test_conv_negative_base_range.out
new file mode 100644
index 00000000000..be2678f7e07
--- /dev/null
+++ 
b/regression-test/data/query_p0/sql_functions/math_functions/test_conv_negative_base_range.out
@@ -0,0 +1,295 @@
+-- This file is automatically generated. You should know what you did if you 
want to edit this
+-- !negative_literals --
+18446744073709551606   18446744073709551606    -10     -10     -2      -2
+
+-- !negative_source_prefix_literals --
+-1     -1      -1      18446744073709551615    -5      -5      -123
+
+-- !base_columns --
+1      18446744073709551606    18446744073709551606
+10     \N      \N
+11     35      \N
+12     2       2
+13     \N      \N
+14     FFFFFFFFFFFFFFFF        \N
+15     1       \N
+16     18446744073709551615    \N
+17     9223372036854775808     9223372036854775808
+18     0       0
+19     18446744073709551606    18446744073709551606
+2      18446744073709551614    18446744073709551614
+20     \N      \N
+21     \N      \N
+22     \N      \N
+23     \N      \N
+24     \N      \N
+25     \N      \N
+26     \N      \N
+27     \N      \N
+28     Z       Z
+29     18446744073709551614    18446744073709551614
+3      FFFFFFFFFFFFFF9C        FFFFFFFFFFFFFF9C
+30     18446744073709551580    18446744073709551580
+31     -1010   -1010
+32     Z       Z
+33     \N      \N
+34     \N      \N
+35     \N      \N
+36     \N      \N
+37     -1      \N
+38     -9223372036854775808    -9223372036854775808
+39     -1      -1
+4      9223372036854775808     9223372036854775808
+40     -1      \N
+41     18446744073709551615    \N
+42     -5      -5
+43     -123    \N
+44     -9223372036854775808    -9223372036854775808
+45     \N      \N
+46     \N      \N
+5      -10     -10
+6      18446744073709551606    18446744073709551606
+7      \N      \N
+8      \N      \N
+9      \N      \N
+
+-- !constant_bases --
+1      18446744073709551606    18446744073709551606
+10     10      10
+11     0       \N
+12     10      10
+13     \N      \N
+14     18446744073709551615    \N
+15     1       \N
+16     18446744073709551615    \N
+17     9223372036854775808     9223372036854775808
+18     0       0
+19     18446744073709551606    18446744073709551606
+2      18446744073709551606    18446744073709551606
+20     10      10
+21     10      10
+22     18446744073709551606    18446744073709551606
+23     18446744073709551606    18446744073709551606
+24     10      10
+25     10      10
+26     10      10
+27     10      10
+28     35      35
+29     18446744073709551606    18446744073709551606
+3      18446744073709551516    18446744073709551516
+30     18446744073709551606    18446744073709551606
+31     18446744073709551606    18446744073709551606
+32     35      35
+33     10      10
+34     10      10
+35     10      10
+36     10      10
+37     18446744073709551615    \N
+38     9223372036854775808     9223372036854775808
+39     18446744073709551495    18446744073709551495
+4      18438744073709551616    18438744073709551616
+40     18446744073709551615    \N
+41     18446744073709551615    \N
+42     18446744073709550604    18446744073709550604
+43     18446744073709551493    \N
+44     9223372036854775808     9223372036854775808
+45     10      10
+46     0       0
+5      18446744073709551606    18446744073709551606
+6      18446744073709551606    18446744073709551606
+7      10      10
+8      10      10
+9      10      10
+
+-- !constant_invalid_bases --
+1      \N      \N
+10     \N      \N
+11     \N      \N
+12     \N      \N
+13     \N      \N
+14     \N      \N
+15     \N      \N
+16     \N      \N
+17     \N      \N
+18     \N      \N
+19     \N      \N
+2      \N      \N
+20     \N      \N
+21     \N      \N
+22     \N      \N
+23     \N      \N
+24     \N      \N
+25     \N      \N
+26     \N      \N
+27     \N      \N
+28     \N      \N
+29     \N      \N
+3      \N      \N
+30     \N      \N
+31     \N      \N
+32     \N      \N
+33     \N      \N
+34     \N      \N
+35     \N      \N
+36     \N      \N
+37     \N      \N
+38     \N      \N
+39     \N      \N
+4      \N      \N
+40     \N      \N
+41     \N      \N
+42     \N      \N
+43     \N      \N
+44     \N      \N
+45     \N      \N
+46     \N      \N
+5      \N      \N
+6      \N      \N
+7      \N      \N
+8      \N      \N
+9      \N      \N
+
+-- !constant_signed_bases --
+1      -10     -10
+10     10      10
+11     0       \N
+12     10      10
+13     \N      \N
+14     -1      \N
+15     1       \N
+16     -1      \N
+17     -9223372036854775808    -9223372036854775808
+18     0       0
+19     -10     -10
+2      -10     -10
+20     10      10
+21     10      10
+22     -10     -10
+23     -10     -10
+24     10      10
+25     10      10
+26     10      10
+27     10      10
+28     35      35
+29     -10     -10
+3      -100    -100
+30     -10     -10
+31     -10     -10
+32     35      35
+33     10      10
+34     10      10
+35     10      10
+36     10      10
+37     -1      \N
+38     -9223372036854775808    -9223372036854775808
+39     -121    -121
+4      -8000000000000000       -8000000000000000
+40     -1      \N
+41     -1      \N
+42     -1012   -1012
+43     -123    \N
+44     -9223372036854775808    -9223372036854775808
+45     10      10
+46     0       0
+5      -10     -10
+6      -10     -10
+7      10      10
+8      10      10
+9      10      10
+
+-- !constant_negative_source_bases --
+1      -2      -2      -10     -10
+10     \N      \N      \N      \N
+11     \N      \N      \N      \N
+12     \N      \N      \N      \N
+13     \N      \N      \N      \N
+14     \N      \N      -1      \N
+15     -1      \N      \N      \N
+16     -1      \N      \N      \N
+17     \N      0       -9223372036854775808    -9223372036854775808
+18     \N      \N      \N      \N
+19     -2      -2      -10     -10
+2      -2      -2      -10     -10
+20     \N      \N      \N      \N
+21     \N      \N      \N      \N
+22     -2      -2      -10     -10
+23     -2      -2      -10     -10
+24     \N      \N      \N      \N
+25     \N      \N      \N      \N
+26     \N      \N      \N      \N
+27     \N      \N      \N      \N
+28     \N      \N      \N      \N
+29     -2      -2      -10     -10
+3      -4      -4      -100    -100
+30     -2      -2      -10     -10
+31     -2      -2      -10     -10
+32     \N      \N      \N      \N
+33     \N      \N      \N      \N
+34     \N      \N      \N      \N
+35     \N      \N      \N      \N
+36     \N      \N      \N      \N
+37     -1      \N      \N      \N
+38     \N      0       -9223372036854775808    -9223372036854775808
+39     -1      -1      -121    -121
+4      \N      0       -8000000000000000       -8000000000000000
+40     -1      \N      -1      \N
+41     -1      \N      -1      \N
+42     -5      -5      -1012   -1012
+43     -1      \N      -123    \N
+44     \N      0       -9223372036854775808    -9223372036854775808
+45     \N      \N      \N      \N
+46     \N      \N      \N      \N
+5      -2      -2      -10     -10
+6      -2      -2      -10     -10
+7      \N      \N      \N      \N
+8      \N      \N      \N      \N
+9      \N      \N      \N      \N
+
+-- !mixed_bases --
+1      18446744073709551606    18446744073709551606
+10     10      \N
+11     35      \N
+12     2       A
+13     \N      \N
+14     18446744073709551615    \N
+15     1       \N
+16     18446744073709551615    \N
+17     9223372036854775808     9223372036854775808
+18     0       0
+19     18446744073709551606    18446744073709551606
+2      18446744073709551614    18446744073709551606
+20     \N      10
+21     10      \N
+22     \N      18446744073709551606
+23     18446744073709551606    \N
+24     \N      10
+25     10      \N
+26     \N      10
+27     10      \N
+28     35      Z
+29     18446744073709551614    18446744073709551606
+3      18446744073709551516    FFFFFFFFFFFFFF9C
+30     18446744073709551580    18446744073709551606
+31     18446744073709551606    -1010
+32     35      Z
+33     \N      10
+34     \N      10
+35     10      \N
+36     10      \N
+37     18446744073709551615    \N
+38     9223372036854775808     -9223372036854775808
+39     18446744073709551615    -121
+4      9223372036854775808     18438744073709551616
+40     18446744073709551615    \N
+41     18446744073709551615    \N
+42     18446744073709551611    -1012
+43     18446744073709551493    \N
+44     9223372036854775808     -9223372036854775808
+45     \N      10
+46     \N      0
+5      18446744073709551606    -10
+6      18446744073709551606    18446744073709551606
+7      \N      10
+8      \N      10
+9      10      \N
+
diff --git 
a/regression-test/suites/query_p0/sql_functions/math_functions/test_conv_negative_base_range.groovy
 
b/regression-test/suites/query_p0/sql_functions/math_functions/test_conv_negative_base_range.groovy
new file mode 100644
index 00000000000..a2a5edce6b8
--- /dev/null
+++ 
b/regression-test/suites/query_p0/sql_functions/math_functions/test_conv_negative_base_range.groovy
@@ -0,0 +1,135 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+suite("test_conv_negative_base_range") {
+    order_qt_negative_literals """
+        SELECT CONV('-10', 10, 10), CONV(-10, 10, 10),
+               CONV('-10', 10, -10), CONV(-10, 10, -10),
+               CONV('-10', 2, -10), CONV(-10, 2, -10)
+    """
+    order_qt_negative_source_prefix_literals """
+        SELECT CONV('-121', -2, -10), CONV(-121, -2, -10),
+               CONV('-1a1', -10, -10), CONV('-1A1', -10, 10),
+               CONV('-1012', -2, -10), CONV(-1012, -2, -10),
+               CONV('-123a9', -10, -10)
+    """
+
+    sql "DROP TABLE IF EXISTS test_conv_negative_base_range"
+    sql """
+        CREATE TABLE test_conv_negative_base_range (
+            id INT,
+            input_str VARCHAR(64),
+            input_num BIGINT,
+            from_base TINYINT,
+            to_base TINYINT
+        ) DISTRIBUTED BY HASH(id) BUCKETS 1
+        PROPERTIES ("replication_num" = "1")
+    """
+    sql """
+        INSERT INTO test_conv_negative_base_range VALUES
+            (1, '-10', -10, 10, 10),
+            (2, '-10', -10, 2, 10),
+            (3, '-100', -100, 10, 16),
+            (4, '-8000000000000000', -8000000000000000, 16, 10),
+            (5, '-10', -10, 10, -10),
+            (6, '-10', -10, -10, 10),
+            (7, '10', 10, 1, 10),
+            (8, '10', 10, 37, 10),
+            (9, '10', 10, 10, 1),
+            (10, '10', 10, 10, 37),
+            (11, 'z', NULL, 36, 10),
+            (12, '10', 10, 2, 36),
+            (13, NULL, NULL, 10, 10),
+            (14, '18446744073709551615', NULL, 10, 16),
+            (15, '-18446744073709551615', NULL, 10, 10),
+            (16, '-18446744073709551616', NULL, 10, 10),
+            (17, '-9223372036854775808', -9223372036854775808, 10, 10),
+            (18, '-0', 0, 10, 10),
+            (19, '  -10  ', -10, 10, 10),
+            (20, '10', 10, NULL, 10),
+            (21, '10', 10, 10, NULL),
+            (22, '-10', -10, -128, 10),
+            (23, '-10', -10, 10, -128),
+            (24, '10', 10, 0, 10),
+            (25, '10', 10, 10, 0),
+            (26, '10', 10, 127, 10),
+            (27, '10', 10, 10, 127),
+            (28, '35', 35, 10, 36),
+            (29, '-10', -10, -2, 10),
+            (30, '-10', -10, -36, 10),
+            (31, '-10', -10, 10, -2),
+            (32, '35', 35, 10, -36),
+            (33, '10', 10, -1, 10),
+            (34, '10', 10, -37, 10),
+            (35, '10', 10, 10, -1),
+            (36, '10', 10, 10, -37),
+            (37, '-18446744073709551616', NULL, 10, -10),
+            (38, '-9223372036854775808', -9223372036854775808, 10, -10),
+            (39, '-121', -121, -2, -10),
+            (40, '-1a1', NULL, -10, -10),
+            (41, '  -1A1  ', NULL, -10, 10),
+            (42, '-1012', -1012, -2, -10),
+            (43, '-123a9', NULL, -10, -10),
+            (44, '-9223372036854775808', -9223372036854775808, -10, -10),
+            (45, '10', 10, -10, -10),
+            (46, '-0', 0, -2, -10)
+    """
+
+    order_qt_base_columns """
+        SELECT id, CONV(input_str, from_base, to_base), CONV(input_num, 
from_base, to_base)
+        FROM test_conv_negative_base_range ORDER BY id
+    """
+    order_qt_constant_bases """
+        SELECT id, CONV(input_str, 10, 10), CONV(input_num, 10, 10)
+        FROM test_conv_negative_base_range ORDER BY id
+    """
+    order_qt_constant_invalid_bases """
+        SELECT id, CONV(input_str, -1, 10), CONV(input_num, 10, -37)
+        FROM test_conv_negative_base_range ORDER BY id
+    """
+    order_qt_constant_signed_bases """
+        SELECT id, CONV(input_str, 10, -10), CONV(input_num, 10, -10)
+        FROM test_conv_negative_base_range ORDER BY id
+    """
+    order_qt_constant_negative_source_bases """
+        SELECT id, CONV(input_str, -2, -10), CONV(input_num, -2, -10),
+               CONV(input_str, -10, -10), CONV(input_num, -10, -10)
+        FROM test_conv_negative_base_range ORDER BY id
+    """
+    order_qt_mixed_bases """
+        SELECT id, CONV(input_str, from_base, 10), CONV(input_num, 10, to_base)
+        FROM test_conv_negative_base_range ORDER BY id
+    """
+
+    check_fold_consistency "conv('-10', 10, 10)"
+    check_fold_consistency "conv('-10', 2, 10)"
+    check_fold_consistency "conv('-10', 10, -10)"
+    check_fold_consistency "conv('-10', 2, -10)"
+    check_fold_consistency "conv('-10', 10, -2)"
+    check_fold_consistency "conv('35', 10, -36)"
+    check_fold_consistency "conv(-10, -10, 10)"
+    check_fold_consistency "conv('-121', -2, -10)"
+    check_fold_consistency "conv(-121, -2, -10)"
+    check_fold_consistency "conv('-1a1', -10, -10)"
+    check_fold_consistency "conv('-1A1', -10, 10)"
+    check_fold_consistency "conv('-1012', -2, -10)"
+    check_fold_consistency "conv('10', 1, 10)"
+    check_fold_consistency "conv(10, 10, 37)"
+    check_fold_consistency "conv('10', -37, 10)"
+    check_fold_consistency "conv(10, 10, -1)"
+    check_fold_consistency "conv('-18446744073709551615', 10, 10)"
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to