Skip to content
Merged
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
16 changes: 13 additions & 3 deletions cpp/src/io/parquet/experimental/variant_extract.cu
Original file line number Diff line number Diff line change
Expand Up @@ -723,12 +723,10 @@ struct cast_variant_fn {
requires(is_variant_numerical<T>)
{
rmm::device_buffer data{num_rows * sizeof(T), stream, mr};

auto grid = cudf::detail::grid_1d{num_rows, block_size};
cast_variant_primitive_kernel<T><<<grid.num_blocks, block_size, 0, stream.value()>>>(
values, {static_cast<T*>(data.data()), static_cast<std::size_t>(num_rows)}, d_null_mask);
CUDF_CUDA_TRY(cudaGetLastError());

auto const null_count =
num_rows - cudf::detail::count_set_bits(d_null_mask, 0, num_rows, stream);
return std::make_unique<column>(desired_type,
Expand Down Expand Up @@ -774,7 +772,6 @@ struct cast_variant_fn {
cast_variant_string_fn fn{values, d_null_mask, nullptr, nullptr, {}};
auto [offsets_column, chars] =
cudf::strings::detail::make_strings_children(fn, num_rows, stream, mr);

auto const null_count =
num_rows - cudf::detail::count_set_bits(d_null_mask, 0, num_rows, stream);
return make_strings_column(num_rows,
Expand Down Expand Up @@ -926,6 +923,19 @@ std::unique_ptr<column> cast_variant(column_view const& values,
rmm::device_async_resource_ref mr)
{
validate_variant_child(values);

switch (desired_type.id()) {
case type_id::INT8:
case type_id::INT16:
case type_id::INT32:
case type_id::INT64:
case type_id::FLOAT32:
case type_id::FLOAT64:
case type_id::BOOL8:
case type_id::STRING: break;
default: CUDF_FAIL("unsupported type for variant cast", std::invalid_argument);
}

size_type const num_rows = values.size();
if (num_rows == 0) { return make_empty_column(desired_type); }

Expand Down
29 changes: 20 additions & 9 deletions cpp/tests/io/experimental/variant_extract_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@
#include <cudf/utilities/span.hpp>

#include <array>
#include <bit>
#include <cstdio>
#include <cstring>
#include <format>
#include <memory>
#include <string>
#include <vector>
Expand Down Expand Up @@ -1112,14 +1114,10 @@ TEST_F(CastVariantTest, EmptyInput)
}
}

TEST_F(CastVariantTest, CastToUnsupportedTargetThrows)
TEST_F(CastVariantTest, UnsupportedTypeThrows)
{
// cast_variant only supports INT8/16/32/64 and STRING targets. Every other target is rejected at
// compile-time dispatch on the requested output type, independent of the input bytes, so a single
// well-formed placeholder row triggers the same throw for all of them.
// Unsupported target types must throw regardless of whether the input is empty or non-empty.
auto stream = cudf::test::get_default_stream();
std::vector<uint8_t> const val{make_variant_primitive(variant_primitive_type::NULLVAL)};
cudf::test::lists_column_wrapper<uint8_t> values(val.begin(), val.end());

std::vector<cudf::type_id> const ids{cudf::type_id::UINT8,
cudf::type_id::UINT16,
Expand All @@ -1133,11 +1131,24 @@ TEST_F(CastVariantTest, CastToUnsupportedTargetThrows)
cudf::type_id::DECIMAL64,
cudf::type_id::DECIMAL128};

// Empty input: the early-return path must still validate the type.
auto const empty_values =
cudf::empty_like(cudf::structs_column_view{make_xyz_three_row_variant()}.child(1));
for (auto const id : ids) {
SCOPED_TRACE(std::string{"target type_id: "} + std::to_string(static_cast<int32_t>(id)));
EXPECT_THROW(static_cast<void>(cudf::io::parquet::experimental::cast_variant(
values, cudf::data_type{id}, stream)),
std::invalid_argument);
*empty_values, cudf::data_type{id}, stream)),
std::invalid_argument)
<< std::format("expected throw for type_id {} on empty input", static_cast<int>(id));
}

// Non-empty input: the dispatch path must also throw for unsupported types.
auto col = make_apache_variant(avf::primitive_int32);

@mhaseeb123 mhaseeb123 Aug 4, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚁🚁🚁 (iykyk 😄)

auto const value = cudf::structs_column_view{col}.get_sliced_child(1, stream);
for (auto const id : ids) {
EXPECT_THROW(static_cast<void>(cudf::io::parquet::experimental::cast_variant(
value, cudf::data_type{id}, stream)),
std::invalid_argument)
<< std::format("expected throw for type_id {} on non-empty input", static_cast<int>(id));
}
}

Expand Down
Loading