Skip to content

[Variant] add variant_to_arrow union builder - #10313

Merged
Jefffrey merged 12 commits into
apache:mainfrom
sdf-jkl:variant-to-union
Aug 16, 2026
Merged

[Variant] add variant_to_arrow union builder#10313
Jefffrey merged 12 commits into
apache:mainfrom
sdf-jkl:variant-to-union

Conversation

@sdf-jkl

@sdf-jkl sdf-jkl commented Jul 9, 2026

Copy link
Copy Markdown
Member

Which issue does this PR close?

The last type to be supported by variant_to_arrow cast.

Rationale for this change

Check issue

What changes are included in this PR?

  • Add variant_to_arrow union cast support + unit tests

Are these changes tested?

  • Yes, unit tests

Are there any user-facing changes?

  • Users can now cast Variant to Union type

Casting Variant to dense or sparse Union dispatches each value to the
union field that most exactly represents its runtime type (lossless
widening allowed, declaration order breaks ties). Null rows land in a
Null-typed child if declared, otherwise the first child, since unions
have no top-level null buffer.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actions github-actions Bot added the parquet-variant parquet-variant* crates label Jul 9, 2026
@sdf-jkl sdf-jkl changed the title add variant_to_arrow union builder [Variant] add variant_to_arrow union builder Jul 9, 2026
@sdf-jkl
sdf-jkl marked this pull request as ready for review July 20, 2026 22:12
@Jefffrey Jefffrey added the enhancement Any new improvement worthy of a entry in the changelog label Aug 5, 2026

@Jefffrey Jefffrey left a comment

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.

disclaimer: this is kinda my first time looking at variant code 😅

Comment thread parquet-variant-compute/src/variant_get.rs
let null_child = fields
.iter()
.position(|(_, field)| field.data_type() == &DataType::Null)
.unwrap_or(0);

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.

do we need to consider nullability of the field?

@sdf-jkl sdf-jkl Aug 6, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I checked the existing Arrow union policy. UnionBuilder::append_null intentionally writes nulls into child arrays, while UnionBuilder::build still creates those child Fields with nullable = false. UnionArray::try_new does not validate field nullability, and union nullness is derived from the selected child array. Therefore the fallback does not need to select a nullable-declared field.

let mut children = Vec::with_capacity(self.fields.len());
let union_fields = self
.fields
.into_iter()
.map(
|(
name,
FieldData {
type_id,
data_type,
mut values_buffer,
slots,
mut null_buffer_builder,
},
)| {
let array_ref = make_array(unsafe {
ArrayDataBuilder::new(data_type.clone())
.add_buffer(values_buffer.finish())
.len(slots)
.nulls(null_buffer_builder.finish())
.build_unchecked()
});
children.push(array_ref);
(type_id, Arc::new(Field::new(name, data_type, false)))
},
)
.collect();
UnionArray::try_new(
union_fields,
self.type_id_builder.into(),
self.value_offset_builder.map(Into::into),
children,
)

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.

the builder thing is a known issue:

i guess its one of those things which is a bit messy in the codebase as is 🤔

Comment thread parquet-variant-compute/src/variant_to_arrow.rs
@sdf-jkl

sdf-jkl commented Aug 6, 2026

Copy link
Copy Markdown
Member Author

Thanks @Jefffrey 🙏

This is not the most Varianty code, mostly about understanding the Union type

@sdf-jkl

sdf-jkl commented Aug 13, 2026

Copy link
Copy Markdown
Member Author

@klion26 please you take a look 🙏

@Jefffrey
Jefffrey merged commit ae4becb into apache:main Aug 16, 2026
19 checks passed
@Jefffrey

Copy link
Copy Markdown
Contributor

thanks @sdf-jkl

MassivePizza pushed a commit to massive-com/arrow-rs that referenced this pull request Aug 19, 2026
# Which issue does this PR close?

<!--
We generally require a GitHub issue to be filed for all bug fixes and
enhancements and this helps us generate change logs for our releases.
You can link an issue to this PR using the GitHub syntax.
-->
The last type to be supported by `variant_to_arrow` cast.

- Closes apache#8477.

# Rationale for this change

Check issue
<!--
Why are you proposing this change? If this is already explained clearly
in the issue then this section is not needed.
Explaining clearly why changes are proposed helps reviewers understand
your changes and offer better suggestions for fixes.
-->

# What changes are included in this PR?

- Add `variant_to_arrow` union cast support + unit tests
<!--
There is no need to duplicate the description in the issue here but it
is sometimes worth providing a summary of the individual changes in this
PR.
-->

# Are these changes tested?

- Yes, unit tests
<!--
We typically require tests for all PRs in order to:
1. Prevent the code from being accidentally broken by subsequent changes
2. Serve as another way to document the expected behavior of the code

If tests are not included in your PR, please explain why (for example,
are they covered by existing tests)?

If this PR claims a performance improvement, please include evidence
such as benchmark results.
-->

# Are there any user-facing changes?

- Users can now cast Variant to Union type
<!--
If there are user-facing changes then we may require documentation to be
updated before approving the PR.

If there are any breaking changes to public APIs, please call them out.
-->

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Jeffrey Vo <jeffrey.vo.australia@gmail.com>
@klion26

klion26 commented Aug 20, 2026

Copy link
Copy Markdown
Member

Thanks for pushing this forward. Sorry for the late reply, a little busy in the inter works the last days. I'll take a look at this and reply if I have any comments

@sdf-jkl
sdf-jkl deleted the variant-to-union branch August 20, 2026 14:28

@klion26 klion26 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@sdf-jkl I've passed the code, and left some comments inline; thanks.

/// type: 0 is the value's natural Arrow type, higher ranks are lossless widenings, and `None`
/// means the child cannot represent the value losslessly. Every pair admitted here must be
/// convertible by the corresponding row builder.
fn union_child_rank(value: &Variant<'_, '_>, data_type: &DataType) -> Option<u8> {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Here we use type-based info to determine which target the current variant should belong to. This seems incorrect

  1. Variant::Int64(1) can't convert to DataType::Int8, but this should valid when calling variant_get
  2. The logic in the current code (json -> variant, and variant spec), treats the exact number the same in Variant::Int64/Int32/Int16 etc(value has no strict type in variant) (like the Equivalence Class in parquet variant spec)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Maybe we can sort the field in the Union, and try the target column in the sorted order like we treat like the json-> variant(from_json.rs in parquet-variant-compute)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement Any new improvement worthy of a entry in the changelog parquet-variant parquet-variant* crates

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Variant] variant_to_arrow types support

3 participants