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 f7f7545901 fix(arrow-json): render coerced f32 as its value in the 
string decoder (#10386)
f7f7545901 is described below

commit f7f754590118d5dda59abbee961543758e236e3c
Author: Haresh Khanna <[email protected]>
AuthorDate: Mon Jul 20 12:52:10 2026 +0100

    fix(arrow-json): render coerced f32 as its value in the string decoder 
(#10386)
    
    # Which issue does this PR close?
    
    
    # Rationale for this change
    
    When coercing a float into a string column, `StringArrayDecoder` ran a
    `f32` through the integer formatter on its raw bits, so it rendered the
    `u32` bit pattern instead of the value (e.g. `1.5f32` → `"1069547520"`).
    The adjacent `f64` arm and `tape.rs` already reconstruct via
    `from_bits`.
    
    # What changes are included in this PR?
    
    The `F32` arm of `StringArrayDecoder` now uses
    `float_formatter.format_finite(f32::from_bits(n))`, matching the `f64`
    arm. Plus a unit test.
    
    # Are these changes tested?
    
    Yes — new `test_serialize_f32_into_string` (fails before the fix, passes
    after); the full `arrow-json` suite passes.
    
    # Are there any user-facing changes?
    
    Yes (bug fix): an `f32` coerced to string now renders its value, not its
    bit pattern. No API changes. Only reachable via `Decoder::serialize`
    with `coerce_primitive`; JSON text decoding was already correct.
---
 arrow-json/src/reader/mod.rs          | 15 +++++++++++++++
 arrow-json/src/reader/string_array.rs |  2 +-
 2 files changed, 16 insertions(+), 1 deletion(-)

diff --git a/arrow-json/src/reader/mod.rs b/arrow-json/src/reader/mod.rs
index c14c1f9ea0..ea4cbe2664 100644
--- a/arrow-json/src/reader/mod.rs
+++ b/arrow-json/src/reader/mod.rs
@@ -2903,6 +2903,21 @@ mod tests {
         );
     }
 
+    #[test]
+    fn test_serialize_f32_into_string() {
+        // Coercing an f32 into a string column must render the value, not its 
raw bit pattern.
+        let field = Field::new("f", DataType::Utf8, true);
+        let mut decoder = ReaderBuilder::new_with_field(field)
+            .with_coerce_primitive(true)
+            .build_decoder()
+            .unwrap();
+        decoder.serialize(&[1.5_f32, -2.25_f32]).unwrap();
+        let batch = decoder.flush().unwrap().unwrap();
+        let values = batch.column(0).as_string::<i32>();
+        assert_eq!(values.value(0), "1.5");
+        assert_eq!(values.value(1), "-2.25");
+    }
+
     // Parse the given `row` in `struct_mode` as a type given by fields.
     //
     // If as_struct == true, wrap the fields in a Struct field with name "r".
diff --git a/arrow-json/src/reader/string_array.rs 
b/arrow-json/src/reader/string_array.rs
index 6b6abc21ed..42ace8ef7d 100644
--- a/arrow-json/src/reader/string_array.rs
+++ b/arrow-json/src/reader/string_array.rs
@@ -120,7 +120,7 @@ impl<O: OffsetSizeTrait> ArrayDecoder for 
StringArrayDecoder<O> {
                     builder.append_value(int_formatter.format(n));
                 }
                 TapeElement::F32(n) if coerce_primitive => {
-                    builder.append_value(int_formatter.format(n));
+                    
builder.append_value(float_formatter.format_finite(f32::from_bits(n)));
                 }
                 TapeElement::F64(high) if coerce_primitive => match tape.get(p 
+ 1) {
                     TapeElement::F32(low) => {

Reply via email to