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),
],
},
],