This is an automated email from the ASF dual-hosted git repository.
Jefffrey pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow-rs.git
The following commit(s) were added to refs/heads/main by this push:
new a5ba6a29d6 fix(arrow-array): `PrimitiveRunBuilder` was buggy after
`finish` (#11326)
a5ba6a29d6 is described below
commit a5ba6a29d63671d4f8ef79f19b78257a8f19c70a
Author: Neil Conway <[email protected]>
AuthorDate: Thu Oct 1 22:23:13 2026 -0400
fix(arrow-array): `PrimitiveRunBuilder` was buggy after `finish` (#11326)
# Which issue does this PR close?
- Closes #11325.
# Rationale for this change
`PrimitiveRunBuilder::finish` did not reset `prev_run_end_index`, so a
reused builder kept the previous batch's last run index. That resulted
in various misbehavior, like either dropping data or panicking, on a
subsequent `finish` call.
# What changes are included in this PR?
See above.
# Are these changes tested?
Yes; new test added.
# Are there any user-facing changes?
No.
# AI usage
Issue spotted and fix developed with Claude Code (Opus 5.5); I have
reviewed and understand the resulting code.
---
arrow-array/src/builder/primitive_run_builder.rs | 20 +++++++++++++++++++-
1 file changed, 19 insertions(+), 1 deletion(-)
diff --git a/arrow-array/src/builder/primitive_run_builder.rs
b/arrow-array/src/builder/primitive_run_builder.rs
index a78e5844ed..ec2f7febc5 100644
--- a/arrow-array/src/builder/primitive_run_builder.rs
+++ b/arrow-array/src/builder/primitive_run_builder.rs
@@ -200,9 +200,10 @@ where
// write the last run end to the array.
self.append_run_end();
- // reset the run index to zero.
+ // reset the run indexes to zero.
self.current_value = None;
self.current_run_end_index = 0;
+ self.prev_run_end_index = 0;
// build the run encoded array by adding run_ends and values array as
its children.
let run_ends_array = self.run_ends_builder.finish();
@@ -333,6 +334,23 @@ mod tests {
);
}
+ #[test]
+ fn test_reuse_after_finish() {
+ let mut builder = PrimitiveRunBuilder::<Int16Type, Int16Type>::new();
+ builder.extend([1, 2, 3].into_iter().map(Some));
+ builder.finish();
+
+ // A single run with the same length as the previous batch
+ builder.extend([7, 7, 7].into_iter().map(Some));
+ let array = builder.finish();
+ assert_eq!(array.len(), 3);
+ assert_eq!(array.run_ends().values(), &[3]);
+ assert_eq!(array.values().as_primitive::<Int16Type>().values(), &[7]);
+
+ // Nothing appended since the last finish
+ assert_eq!(builder.finish().len(), 0);
+ }
+
#[test]
#[should_panic(expected = "incompatible data type for builder")]
fn test_override_data_type_invalid() {