Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions cpp/src/gandiva/gdv_function_stubs_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,31 @@ TEST(TestGdvFnStubs, TestCastVARCHARFromMilliseconds) {
ctx.Reset();
}

TEST(TestGdvFnStubs, TestCastVARCHARFromMillisecondsOutOfRange) {
gandiva::ExecutionContext ctx;
int64_t ctx_ptr = reinterpret_cast<int64_t>(&ctx);
int32_t len_a = 0, len_b = 0;

// date64 is in milliseconds; this value is far past the year range the
// formatter can print, so StringFormatter<Date64Type> emits the longer
// "<value out of range: ...>" rendering, which is well over 10 bytes.
gdv_date64 out_of_range = 9000000000000000LL;
const char* a = gdv_fn_castVARCHAR_date64_int64(ctx_ptr, out_of_range, 100, &len_a);
std::string expected_a(a, len_a);
EXPECT_EQ(expected_a, "<value out of range: 9000000000000000>");
EXPECT_FALSE(ctx.has_error());

// The next cast reuses the same arena chunk immediately after `a`. If `a` only
// reserved 10 bytes the longer write ran past its slot, so this allocation
// overlaps and corrupts it; with the buffer sized for the real output the two
// do not overlap and `a` is still intact here.
gdv_date64 ts = StringToTimestamp("2021-04-23 10:20:33");
gdv_fn_castVARCHAR_date64_int64(ctx_ptr, ts, 100, &len_b);
EXPECT_FALSE(ctx.has_error());
EXPECT_EQ(std::string(a, len_a), expected_a);
ctx.Reset();
}

TEST(TestGdvFnStubs, TestCastVARCHARFromFloat) {
gandiva::ExecutionContext ctx;
uint64_t ctx_ptr = reinterpret_cast<int64_t>(&ctx);
Expand Down
8 changes: 6 additions & 2 deletions cpp/src/gandiva/gdv_string_function_stubs.cc
Original file line number Diff line number Diff line change
Expand Up @@ -160,10 +160,14 @@ const char* gdv_fn_regexp_extract_utf8_utf8_int32(int64_t ptr, int64_t holder_pt
return ret; \
}

// Macro for date64 type. Output is always "YYYY-MM-DD" = 10 chars max.
// Macro for date64 type. StringFormatter<Date64Type> emits "YYYY-MM-DD" for
// ordinary dates, but widens to "-YYYYY-MM-DD" for years outside four digits and
// to "<value out of range: <int64>>" for millisecond values beyond its supported
// year range, so the rendering can be well over 10 bytes. Size the buffer for the
// longest one: "<value out of range: " (21) + up to 20 int64 digits + ">" (1).
#define GDV_FN_CAST_VARLEN_TYPE_FROM_DATE64(IN_TYPE, CAST_NAME, ARROW_TYPE) \
GDV_FN_CAST_VARLEN_PREFIX(IN_TYPE, CAST_NAME) \
constexpr int32_t max_date_str_len = 10; \
constexpr int32_t max_date_str_len = 42; \
int32_t alloc_len = \
static_cast<int32_t>(len < max_date_str_len ? len : max_date_str_len); \
GDV_FN_CAST_VARLEN_ALLOC(alloc_len) \
Expand Down
Loading