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]