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

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


The following commit(s) were added to refs/heads/main by this push:
     new 29586f4d28 GH-48703: [Ruby] Add support for reading decimal256 array 
(#48704)
29586f4d28 is described below

commit 29586f4d28c50a4344f14a78dc7e091ab635fa72
Author: Sutou Kouhei <[email protected]>
AuthorDate: Fri Jan 2 15:31:27 2026 +0900

    GH-48703: [Ruby] Add support for reading decimal256 array (#48704)
    
    ### Rationale for this change
    
    It's a 256 bit variant of decimal array.
    
    ### What changes are included in this PR?
    
    * Add `ArrowFormat::Decimal256Type`
    * Add `ArrowFormat::Decimal256Array`
    
    ### Are these changes tested?
    
    Yes.
    
    ### Are there any user-facing changes?
    
    Yes.
    
    * GitHub Issue: #48703
    
    Authored-by: Sutou Kouhei <[email protected]>
    Signed-off-by: Sutou Kouhei <[email protected]>
---
 ruby/red-arrow-format/lib/arrow-format/array.rb    | 39 +++++++++++-----
 ruby/red-arrow-format/lib/arrow-format/readable.rb |  2 +
 ruby/red-arrow-format/lib/arrow-format/type.rb     | 14 ++++++
 ruby/red-arrow-format/test/test-reader.rb          | 52 +++++++++++++++++++---
 4 files changed, 91 insertions(+), 16 deletions(-)

diff --git a/ruby/red-arrow-format/lib/arrow-format/array.rb 
b/ruby/red-arrow-format/lib/arrow-format/array.rb
index 6474869c30..9d82aae16f 100644
--- a/ruby/red-arrow-format/lib/arrow-format/array.rb
+++ b/ruby/red-arrow-format/lib/arrow-format/array.rb
@@ -309,12 +309,9 @@ module ArrowFormat
   end
 
   class DecimalArray < FixedSizeBinaryArray
-  end
-
-  class Decimal128Array < DecimalArray
     def to_a
       byte_width = @type.byte_width
-      buffer_types = [:u64, :s64] # TODO: big endian support
+      buffer_types = [:u64] * (byte_width / 8 - 1) + [:s64]
       values = 0.step(@size * byte_width - 1, byte_width).collect do |offset|
         @values_buffer.get_values(buffer_types, offset)
       end
@@ -322,27 +319,47 @@ module ArrowFormat
         if value.nil?
           nil
         else
-          low, high = value
-          BigDecimal(format_value(low, high))
+          BigDecimal(format_value(value))
         end
       end
     end
 
     private
-    def format_value(low, high)
+    def format_value(components)
+      highest = components.last
       width = @type.precision
-      width += 1 if high < 0
-      value = (high << 64) + low
-      string = value.to_s.ljust(width, "0")
+      width += 1 if highest < 0
+      value = 0
+      components.reverse_each do |component|
+        value = (value << 64) + component
+      end
+      string = value.to_s
       if @type.scale < 0
         string << ("0" * [email protected])
       elsif @type.scale > 0
-        string[[email protected], 0] = "."
+        n_digits = string.bytesize
+        n_digits -= 1 if value < 0
+        if n_digits < @type.scale
+          prefix = "0." + ("0" * (@type.scale - n_digits - 1))
+          if value < 0
+            string[1, 0] = prefix
+          else
+            string[0, 0] = prefix
+          end
+        else
+          string[[email protected], 0] = "."
+        end
       end
       string
     end
   end
 
+  class Decimal128Array < DecimalArray
+  end
+
+  class Decimal256Array < DecimalArray
+  end
+
   class VariableSizeListArray < Array
     def initialize(type, size, validity_buffer, offsets_buffer, child)
       super(type, size, validity_buffer)
diff --git a/ruby/red-arrow-format/lib/arrow-format/readable.rb 
b/ruby/red-arrow-format/lib/arrow-format/readable.rb
index 5a247c822a..7aa2effde2 100644
--- a/ruby/red-arrow-format/lib/arrow-format/readable.rb
+++ b/ruby/red-arrow-format/lib/arrow-format/readable.rb
@@ -171,6 +171,8 @@ module ArrowFormat
         case fb_type.bit_width
         when 128
           type = Decimal128Type.new(fb_type.precision, fb_type.scale)
+        when 256
+          type = Decimal256Type.new(fb_type.precision, fb_type.scale)
         end
       end
       Field.new(fb_field.name, type, fb_field.nullable?)
diff --git a/ruby/red-arrow-format/lib/arrow-format/type.rb 
b/ruby/red-arrow-format/lib/arrow-format/type.rb
index d6d8b7bb81..92a699509b 100644
--- a/ruby/red-arrow-format/lib/arrow-format/type.rb
+++ b/ruby/red-arrow-format/lib/arrow-format/type.rb
@@ -522,6 +522,20 @@ module ArrowFormat
     end
   end
 
+  class Decimal256Type < DecimalType
+    def initialize(precision, scale)
+      super(32, precision, scale)
+    end
+
+    def name
+      "Decimal256"
+    end
+
+    def build_array(size, validity_buffer, values_buffer)
+      Decimal256Array.new(self, size, validity_buffer, values_buffer)
+    end
+  end
+
   class VariableSizeListType < Type
     attr_reader :child
     def initialize(child)
diff --git a/ruby/red-arrow-format/test/test-reader.rb 
b/ruby/red-arrow-format/test/test-reader.rb
index cddcea484f..8164d20623 100644
--- a/ruby/red-arrow-format/test/test-reader.rb
+++ b/ruby/red-arrow-format/test/test-reader.rb
@@ -676,19 +676,61 @@ module ReaderTests
 
         sub_test_case("Decimal128") do
           def build_array
-            @positive = "12345678901234567890123456789012345.678"
-            @negative = "-12345678901234567890123456789012345.67"
+            @positive_small = "1.200"
+            @positive_large = ("1234567890" * 3) + "12345.678"
+            @negative_small = "-1.200"
+            @negative_large = "-" + ("1234567890" * 3) + "12345.678"
             Arrow::Decimal128Array.new({precision: 38, scale: 3},
-                                       [@positive, nil, @negative])
+                                       [
+                                         @positive_large,
+                                         @positive_small,
+                                         nil,
+                                         @negative_small,
+                                         @negative_large,
+                                       ])
           end
 
           def test_read
             assert_equal([
                            {
                              "value" => [
-                               BigDecimal(@positive),
+                               BigDecimal(@positive_large),
+                               BigDecimal(@positive_small),
                                nil,
-                               BigDecimal(@negative),
+                               BigDecimal(@negative_small),
+                               BigDecimal(@negative_large),
+                             ],
+                           },
+                         ],
+                         read)
+          end
+        end
+
+        sub_test_case("Decimal256") do
+          def build_array
+            @positive_small = "1.200"
+            @positive_large = ("1234567890" * 7) + "123.456"
+            @negative_small = "-1.200"
+            @negative_large = "-" + ("1234567890" * 7) + "123.456"
+            Arrow::Decimal256Array.new({precision: 76, scale: 3},
+                                       [
+                                         @positive_large,
+                                         @positive_small,
+                                         nil,
+                                         @negative_small,
+                                         @negative_large,
+                                       ])
+          end
+
+          def test_read
+            assert_equal([
+                           {
+                             "value" => [
+                               BigDecimal(@positive_large),
+                               BigDecimal(@positive_small),
+                               nil,
+                               BigDecimal(@negative_small),
+                               BigDecimal(@negative_large),
                              ],
                            },
                          ],

Reply via email to