diff --git a/cpp/src/gandiva/gdv_function_stubs_test.cc b/cpp/src/gandiva/gdv_function_stubs_test.cc index cbe24b74236f..a423d8dd85d7 100644 --- a/cpp/src/gandiva/gdv_function_stubs_test.cc +++ b/cpp/src/gandiva/gdv_function_stubs_test.cc @@ -21,6 +21,8 @@ #include #include +#include + #include "arrow/util/logging.h" #include "gandiva/execution_context.h" @@ -526,6 +528,21 @@ TEST(TestGdvFnStubs, TestSubstringIndex) { out_str = gdv_fn_substring_index(ctx_ptr, "路学\\L", 8, "\\", 1, -1, &out_len); EXPECT_EQ(std::string(out_str, out_len), "L"); EXPECT_FALSE(ctx.has_error()); + + // Large counts return full string when delimiter not found enough times + out_str = gdv_fn_substring_index(ctx_ptr, "a.b.c", 5, ".", 1, -1000, &out_len); + EXPECT_EQ(std::string(out_str, out_len), "a.b.c"); + EXPECT_FALSE(ctx.has_error()); + + out_str = gdv_fn_substring_index(ctx_ptr, "a.b.c", 5, ".", 1, + std::numeric_limits::max(), &out_len); + EXPECT_EQ(std::string(out_str, out_len), "a.b.c"); + EXPECT_FALSE(ctx.has_error()); + + out_str = gdv_fn_substring_index(ctx_ptr, "a.b.c", 5, ".", 1, + std::numeric_limits::min(), &out_len); + EXPECT_EQ(std::string(out_str, out_len), "a.b.c"); + EXPECT_FALSE(ctx.has_error()); } TEST(TestGdvFnStubs, TestUpper) { diff --git a/cpp/src/gandiva/gdv_string_function_stubs.cc b/cpp/src/gandiva/gdv_string_function_stubs.cc index e7982461b439..4e62d24a7b2c 100644 --- a/cpp/src/gandiva/gdv_string_function_stubs.cc +++ b/cpp/src/gandiva/gdv_string_function_stubs.cc @@ -407,14 +407,17 @@ const char* gdv_fn_substring_index(int64_t context, const char* txt, int32_t txt } } - if (static_cast(abs(cnt)) <= static_cast(occ.size()) && cnt > 0) { + // Use int64_t to avoid undefined behavior with abs(INT_MIN) + int64_t abs_cnt = (cnt < 0) ? -static_cast(cnt) : static_cast(cnt); + int64_t occ_size = static_cast(occ.size()); + + if (abs_cnt <= occ_size && cnt > 0) { memcpy(out, txt, occ[cnt - 1]); *out_len = occ[cnt - 1]; return out; - } else if (static_cast(abs(cnt)) <= static_cast(occ.size()) && - cnt < 0) { + } else if (abs_cnt <= occ_size && cnt < 0) { int32_t sz = static_cast(occ.size()); - int32_t temp = static_cast(abs(cnt)); + int32_t temp = static_cast(abs_cnt); memcpy(out, txt + occ[sz - temp] + pat_len, txt_len - occ[sz - temp] - pat_len); *out_len = txt_len - occ[sz - temp] - pat_len; diff --git a/cpp/src/gandiva/precompiled/extended_math_ops.cc b/cpp/src/gandiva/precompiled/extended_math_ops.cc index b2562e955acd..c29f8f2a8684 100644 --- a/cpp/src/gandiva/precompiled/extended_math_ops.cc +++ b/cpp/src/gandiva/precompiled/extended_math_ops.cc @@ -386,16 +386,22 @@ gdv_int64 get_power_of_10(gdv_int32 exp) { FORCE_INLINE gdv_int64 truncate_int64_int32(gdv_int64 in, gdv_int32 out_scale) { + // For int64 (no fractional digits), positive scale is a no-op + if (out_scale >= 0) { + return in; + } + // GetScaleMultiplier only supports scales 0-38 + if (out_scale < -38) { + return 0; + } + bool overflow = false; arrow::BasicDecimal128 decimal = gandiva::decimalops::FromInt64(in, 38, 0, &overflow); arrow::BasicDecimal128 decimal_with_outscale = gandiva::decimalops::Truncate(gandiva::BasicDecimalScalar128(decimal, 38, 0), 38, out_scale, out_scale, &overflow); - if (out_scale < 0) { - out_scale = 0; - } return gandiva::decimalops::ToInt64( - gandiva::BasicDecimalScalar128(decimal_with_outscale, 38, out_scale), &overflow); + gandiva::BasicDecimalScalar128(decimal_with_outscale, 38, 0), &overflow); } FORCE_INLINE diff --git a/cpp/src/gandiva/precompiled/extended_math_ops_test.cc b/cpp/src/gandiva/precompiled/extended_math_ops_test.cc index 7170fad01d25..ad0cb78188c5 100644 --- a/cpp/src/gandiva/precompiled/extended_math_ops_test.cc +++ b/cpp/src/gandiva/precompiled/extended_math_ops_test.cc @@ -22,6 +22,7 @@ #include #include +#include #include "gandiva/execution_context.h" #include "gandiva/precompiled/types.h" @@ -208,6 +209,18 @@ TEST(TestExtendedMathOps, TestTruncate) { EXPECT_EQ(truncate_int64_int32(-1234, -2), -1200); EXPECT_EQ(truncate_int64_int32(8124674407369523212, 0), 8124674407369523212); EXPECT_EQ(truncate_int64_int32(8124674407369523212, -2), 8124674407369523200); + + // Positive scales are no-op for int64 (no fractional digits) + EXPECT_EQ(truncate_int64_int32(12345, std::numeric_limits::max()), 12345); + EXPECT_EQ(truncate_int64_int32(-12345, std::numeric_limits::max()), -12345); + EXPECT_EQ(truncate_int64_int32(12345, 100), 12345); + EXPECT_EQ(truncate_int64_int32(12345, 39), 12345); + + // Scales beyond [-38, 0) truncate all digits + EXPECT_EQ(truncate_int64_int32(12345, std::numeric_limits::min()), 0); + EXPECT_EQ(truncate_int64_int32(12345, -100), 0); + EXPECT_EQ(truncate_int64_int32(12345, -39), 0); + EXPECT_EQ(truncate_int64_int32(-99999, -39), 0); } TEST(TestExtendedMathOps, TestTrigonometricFunctions) {