This is an automated email from the ASF dual-hosted git repository.

zeroshade pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow-go.git


The following commit(s) were added to refs/heads/main by this push:
     new ed543050 fix(arrow/scalar): preserve exact decimal string casts (#1107)
ed543050 is described below

commit ed543050a287d66c8a6652ea6826bccf7a08d96a
Author: Minh Vu <[email protected]>
AuthorDate: Fri Aug 7 20:43:47 2026 +0200

    fix(arrow/scalar): preserve exact decimal string casts (#1107)
    
    ### Rationale for this change
    
    Decimal string casts build their scale factor through math.Pow10 and
    float64. Large decimal scales can therefore lose precision even though
    the decimal types already provide an exact conversion.
    
    ### What changes are included in this PR?
    
    Use the existing exact conversion for Decimal128 and Decimal256 string
    casts and add high-precision coverage for both types.
    
    ### Are these changes tested?
    
    - `go test ./arrow/scalar`
    
    ### Are there any user-facing changes?
    
    No API changes. This corrects the reported behavior while preserving the
    existing ownership and compatibility contracts.
---
 arrow/scalar/scalar.go      |  9 ++-------
 arrow/scalar/scalar_test.go | 18 ++++++++++++++++++
 2 files changed, 20 insertions(+), 7 deletions(-)

diff --git a/arrow/scalar/scalar.go b/arrow/scalar/scalar.go
index 5b9bcac1..8cb31764 100644
--- a/arrow/scalar/scalar.go
+++ b/arrow/scalar/scalar.go
@@ -21,7 +21,6 @@ import (
        "errors"
        "fmt"
        "math"
-       "math/big"
        "reflect"
        "strconv"
        "unsafe"
@@ -329,9 +328,7 @@ func (s *Decimal128) CastTo(to arrow.DataType) (Scalar, 
error) {
                return NewDecimal256Scalar(newVal, to), nil
        case arrow.STRING:
                dt := s.Type.(*arrow.Decimal128Type)
-               scale := big.NewFloat(math.Pow10(int(dt.Scale)))
-               val := (&big.Float{}).SetInt(s.Value.BigInt())
-               return NewStringScalar(val.Quo(val, scale).Text('g', 
int(dt.Precision))), nil
+               return NewStringScalar(s.Value.ToBigFloat(dt.Scale).Text('g', 
int(dt.Precision))), nil
        }
 
        return nil, fmt.Errorf("cannot cast non-nil decimal128 scalar to type 
%s", to)
@@ -386,9 +383,7 @@ func (s *Decimal256) CastTo(to arrow.DataType) (Scalar, 
error) {
                }
                return NewDecimal256Scalar(newVal, to), nil
        case arrow.STRING:
-               scale := big.NewFloat(math.Pow10(int(dt.Scale)))
-               val := (&big.Float{}).SetInt(s.Value.BigInt())
-               return NewStringScalar(val.Quo(val, scale).Text('g', 
int(dt.Precision))), nil
+               return NewStringScalar(s.Value.ToBigFloat(dt.Scale).Text('g', 
int(dt.Precision))), nil
        }
 
        return nil, fmt.Errorf("cannot cast non-nil decimal256 scalar to type 
%s", to)
diff --git a/arrow/scalar/scalar_test.go b/arrow/scalar/scalar_test.go
index 16366a7d..efb5088a 100644
--- a/arrow/scalar/scalar_test.go
+++ b/arrow/scalar/scalar_test.go
@@ -163,6 +163,24 @@ func TestBasicDecimal256(t *testing.T) {
        assert.False(t, scalar.Equals(pi, pi2))
 }
 
+func TestDecimalScalarStringCastUsesExactScaling(t *testing.T) {
+       decimal128Type := &arrow.Decimal128Type{Precision: 38, Scale: 20}
+       decimal128Value, err := 
decimal128.FromString("-123456789012345678.90123456789012345678", 
decimal128Type.Precision, decimal128Type.Scale)
+       require.NoError(t, err)
+       decimal128Scalar := scalar.NewDecimal128Scalar(decimal128Value, 
decimal128Type)
+       cast128, err := decimal128Scalar.CastTo(arrow.BinaryTypes.String)
+       require.NoError(t, err)
+       assert.Equal(t, "-123456789012345678.90123456789012345678", 
cast128.String())
+
+       decimal256Type := &arrow.Decimal256Type{Precision: 76, Scale: 76}
+       decimal256Value, err := 
decimal256.FromString("-0.1234567812345678123456781234567812345678123456781234567812345678123456781234",
 decimal256Type.Precision, decimal256Type.Scale)
+       require.NoError(t, err)
+       decimal256Scalar := scalar.NewDecimal256Scalar(decimal256Value, 
decimal256Type)
+       cast256, err := decimal256Scalar.CastTo(arrow.BinaryTypes.String)
+       require.NoError(t, err)
+       assert.Equal(t, 
"-0.1234567812345678123456781234567812345678123456781234567812345678123456781234",
 cast256.String())
+}
+
 func TestBinaryScalarBasics(t *testing.T) {
        data := "test data"
        buf := memory.NewBufferBytes([]byte(data))

Reply via email to