This is an automated email from the ASF dual-hosted git repository.
pitrou 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 ee6ff0a1b6 GH-50660: [C++][Dev] Add Decimal32 and Decimal64 GDB
pretty-printers (#50723)
ee6ff0a1b6 is described below
commit ee6ff0a1b6b1bceedcea868265b4b0965d0056d0
Author: fenfeng9 <[email protected]>
AuthorDate: Thu Jul 30 16:23:37 2026 +0800
GH-50660: [C++][Dev] Add Decimal32 and Decimal64 GDB pretty-printers
(#50723)
### Rationale for this change
The Arrow GDB pretty-printers support `Decimal128` and `Decimal256`, but do
not support `Decimal32` or `Decimal64`.
### What changes are included in this PR?
* Add GDB pretty-printer support and tests for `Decimal32` and `Decimal64`.
* Remove the unused `max_type_id` variable.
### Are these changes tested?
Yes.
### Are there any user-facing changes?
No.
* GitHub Issue: #50660
Authored-by: fenfeng9 <[email protected]>
Signed-off-by: Antoine Pitrou <[email protected]>
---
cpp/gdb_arrow.py | 35 +++++++++++----
python/pyarrow/src/arrow/python/gdb.cc | 32 ++++++++++++++
python/pyarrow/tests/test_gdb.py | 79 ++++++++++++++++++++++++++++++++++
3 files changed, 138 insertions(+), 8 deletions(-)
diff --git a/cpp/gdb_arrow.py b/cpp/gdb_arrow.py
index 7c95a7c72b..bab1fa8722 100644
--- a/cpp/gdb_arrow.py
+++ b/cpp/gdb_arrow.py
@@ -858,16 +858,19 @@ class MetadataPtr(Sequence):
return self.md[i]
-DecimalTraits = namedtuple('DecimalTraits', ('bit_width', 'struct_format_le'))
+DecimalTraits = namedtuple(
+ 'DecimalTraits', ('bit_width', 'struct_format_le', 'storage_member'))
decimal_traits = {
- 128: DecimalTraits(128, 'Qq'),
- 256: DecimalTraits(256, 'QQQq'),
+ 32: DecimalTraits(32, 'i', 'value_'),
+ 64: DecimalTraits(64, 'q', 'value_'),
+ 128: DecimalTraits(128, 'Qq', 'array_'),
+ 256: DecimalTraits(256, 'QQQq', 'array_'),
}
class BaseDecimal:
"""
- Base class for arrow::BasicDecimal{128,256...} values.
+ Base class for arrow::BasicDecimal{32,64,128,256...} values.
"""
def __init__(self, address):
@@ -877,9 +880,9 @@ class BaseDecimal:
def from_value(cls, val):
"""
Create a decimal from a gdb.Value representing the corresponding
- arrow::BasicDecimal{128,256...}.
+ arrow::BasicDecimal{32,64,128,256...}.
"""
- return cls(val['array_'].address)
+ return cls(val[cls.traits.storage_member].address)
@classmethod
def from_address(cls, address):
@@ -926,6 +929,14 @@ class BaseDecimal:
return str(decimal.Decimal(v).scaleb(-scale))
+class Decimal32(BaseDecimal):
+ traits = decimal_traits[32]
+
+
+class Decimal64(BaseDecimal):
+ traits = decimal_traits[64]
+
+
class Decimal128(BaseDecimal):
traits = decimal_traits[128]
@@ -935,6 +946,8 @@ class Decimal256(BaseDecimal):
decimal_bits_to_class = {
+ 32: Decimal32,
+ 64: Decimal64,
128: Decimal128,
256: Decimal256,
}
@@ -1039,6 +1052,8 @@ type_reprs = {
'DayTimeIntervalType': 'day_time_interval',
'MonthDayNanoIntervalType': 'month_day_nano_interval',
'DurationType': 'duration',
+ 'Decimal32Type': 'decimal32',
+ 'Decimal64Type': 'decimal64',
'Decimal128Type': 'decimal128',
'Decimal256Type': 'decimal256',
'StringType': 'utf8',
@@ -2061,6 +2076,8 @@ type_traits_by_id = {
Type.INTERVAL_MONTH_DAY_NANO: DataTypeTraits(MonthDayNanoIntervalTypeClass,
'MonthDayNanoIntervalType'),
+ Type.DECIMAL32: DataTypeTraits(DecimalTypeClass, 'Decimal32Type'),
+ Type.DECIMAL64: DataTypeTraits(DecimalTypeClass, 'Decimal64Type'),
Type.DECIMAL128: DataTypeTraits(DecimalTypeClass, 'Decimal128Type'),
Type.DECIMAL256: DataTypeTraits(DecimalTypeClass, 'Decimal256Type'),
@@ -2078,8 +2095,6 @@ type_traits_by_id = {
Type.EXTENSION: DataTypeTraits(ExtensionTypeClass, 'ExtensionType'),
}
-max_type_id = len(type_traits_by_id) - 1
-
def lookup_type_class(type_id):
"""
@@ -2368,11 +2383,15 @@ class DecimalPrinter:
printers = {
"arrow::ArrayData": ArrayDataPrinter,
+ "arrow::BasicDecimal32": partial(DecimalPrinter, 32),
+ "arrow::BasicDecimal64": partial(DecimalPrinter, 64),
"arrow::BasicDecimal128": partial(DecimalPrinter, 128),
"arrow::BasicDecimal256": partial(DecimalPrinter, 256),
"arrow::ChunkedArray": ChunkedArrayPrinter,
"arrow::Datum": DatumPrinter,
"arrow::DayTimeIntervalType::DayMilliseconds": DayMillisecondsPrinter,
+ "arrow::Decimal32": partial(DecimalPrinter, 32),
+ "arrow::Decimal64": partial(DecimalPrinter, 64),
"arrow::Decimal128": partial(DecimalPrinter, 128),
"arrow::Decimal256": partial(DecimalPrinter, 256),
"arrow::MonthDayNanoIntervalType::MonthDayNanos": MonthDayNanosPrinter,
diff --git a/python/pyarrow/src/arrow/python/gdb.cc
b/python/pyarrow/src/arrow/python/gdb.cc
index 89135239f2..4442cc4321 100644
--- a/python/pyarrow/src/arrow/python/gdb.cc
+++ b/python/pyarrow/src/arrow/python/gdb.cc
@@ -145,6 +145,18 @@ void TestSession() {
{"key_text", "key_binary"}, {"some value", std::string("z") + '\x00' +
"\x1f\xff"});
// Decimals
+ Decimal32 decimal32_zero{};
+ Decimal32 decimal32_pos{"987654321"};
+ Decimal32 decimal32_neg{"-987654321"};
+ BasicDecimal32 basic_decimal32_zero{};
+ BasicDecimal32 basic_decimal32_pos{decimal32_pos.value()};
+ BasicDecimal32 basic_decimal32_neg{decimal32_neg.value()};
+ Decimal64 decimal64_zero{};
+ Decimal64 decimal64_pos{"987654321098765432"};
+ Decimal64 decimal64_neg{"-987654321098765432"};
+ BasicDecimal64 basic_decimal64_zero{};
+ BasicDecimal64 basic_decimal64_pos{decimal64_pos.value()};
+ BasicDecimal64 basic_decimal64_neg{decimal64_neg.value()};
Decimal128 decimal128_zero{};
Decimal128 decimal128_pos{"98765432109876543210987654321098765432"};
Decimal128 decimal128_neg{"-98765432109876543210987654321098765432"};
@@ -194,8 +206,12 @@ void TestSession() {
FixedSizeBinaryType fixed_size_binary_type(10);
auto heap_fixed_size_binary_type = fixed_size_binary(10);
+ Decimal32Type decimal32_type(8, 3);
+ Decimal64Type decimal64_type(16, 5);
Decimal128Type decimal128_type(16, 5);
Decimal256Type decimal256_type(42, 12);
+ auto heap_decimal32_type = decimal32(8, 3);
+ auto heap_decimal64_type = decimal64(16, 5);
auto heap_decimal128_type = decimal128(16, 5);
ListType list_type(uint8());
@@ -300,6 +316,17 @@ void TestSession() {
Date64Scalar date64_scalar{45 * 86400000LL};
Date64Scalar date64_scalar_null{};
+ Decimal32Scalar decimal32_scalar_pos{Decimal32("1234567"), decimal32(9, 4)};
+ Decimal32Scalar decimal32_scalar_neg{Decimal32("-1234567"), decimal32(9, 4)};
+ Decimal32Scalar decimal32_scalar_null{decimal32(9, 4)};
+ auto heap_decimal32_scalar = *MakeScalar(decimal32(9, 4),
Decimal32("1234567"));
+
+ Decimal64Scalar decimal64_scalar_pos{Decimal64("12345678901234567"),
decimal64(18, 4)};
+ Decimal64Scalar decimal64_scalar_neg{Decimal64("-12345678901234567"),
decimal64(18, 4)};
+ Decimal64Scalar decimal64_scalar_null{decimal64(18, 4)};
+ auto heap_decimal64_scalar =
+ *MakeScalar(decimal64(18, 4), Decimal64("12345678901234567"));
+
Decimal128Scalar decimal128_scalar_pos_scale_pos{Decimal128("1234567"),
decimal128(10, 4)};
Decimal128Scalar decimal128_scalar_pos_scale_neg{Decimal128("-1234567"),
@@ -467,11 +494,16 @@ void TestSession() {
auto heap_timestamp_array_ns = SliceArrayFromJSON(
timestamp(TimeUnit::NANO), R"([null, "1900-02-28 12:34:56.987654321"])");
+ auto heap_decimal32_array =
+ SliceArrayFromJSON(decimal32(9, 4), R"([null, "-12345.6789",
"12345.6789"])");
+ auto heap_decimal64_array = SliceArrayFromJSON(
+ decimal64(18, 4), R"([null, "-12345678901234.5678",
"12345678901234.5678"])");
auto heap_decimal128_array = SliceArrayFromJSON(
decimal128(30, 6),
R"([null, "-1234567890123456789.012345",
"1234567890123456789.012345"])");
auto heap_decimal256_array = SliceArrayFromJSON(
decimal256(50, 6), R"([null,
"-123456789012345678901234567890123456789.012345"])");
+ auto heap_decimal32_array_sliced = heap_decimal32_array->Slice(1, 1);
auto heap_decimal128_array_sliced = heap_decimal128_array->Slice(1, 1);
auto heap_fixed_size_binary_array =
BinaryArrayFromStrings<FixedSizeBinaryBuilder>(
diff --git a/python/pyarrow/tests/test_gdb.py b/python/pyarrow/tests/test_gdb.py
index 912953ae60..cd44e686bb 100644
--- a/python/pyarrow/tests/test_gdb.py
+++ b/python/pyarrow/tests/test_gdb.py
@@ -286,6 +286,32 @@ def test_buffer_heap(gdb_arrow):
def test_decimals(gdb_arrow):
+ v32 = "987654321"
+ check_stack_repr(gdb_arrow, "decimal32_zero", "arrow::Decimal32(0)")
+ check_stack_repr(gdb_arrow, "decimal32_pos",
+ f"arrow::Decimal32({v32})")
+ check_stack_repr(gdb_arrow, "decimal32_neg",
+ f"arrow::Decimal32(-{v32})")
+ check_stack_repr(gdb_arrow, "basic_decimal32_zero",
+ "arrow::BasicDecimal32(0)")
+ check_stack_repr(gdb_arrow, "basic_decimal32_pos",
+ f"arrow::BasicDecimal32({v32})")
+ check_stack_repr(gdb_arrow, "basic_decimal32_neg",
+ f"arrow::BasicDecimal32(-{v32})")
+
+ v64 = "987654321098765432"
+ check_stack_repr(gdb_arrow, "decimal64_zero", "arrow::Decimal64(0)")
+ check_stack_repr(gdb_arrow, "decimal64_pos",
+ f"arrow::Decimal64({v64})")
+ check_stack_repr(gdb_arrow, "decimal64_neg",
+ f"arrow::Decimal64(-{v64})")
+ check_stack_repr(gdb_arrow, "basic_decimal64_zero",
+ "arrow::BasicDecimal64(0)")
+ check_stack_repr(gdb_arrow, "basic_decimal64_pos",
+ f"arrow::BasicDecimal64({v64})")
+ check_stack_repr(gdb_arrow, "basic_decimal64_neg",
+ f"arrow::BasicDecimal64(-{v64})")
+
v128 = "98765432109876543210987654321098765432"
check_stack_repr(gdb_arrow, "decimal128_zero", "arrow::Decimal128(0)")
check_stack_repr(gdb_arrow, "decimal128_pos",
@@ -359,6 +385,10 @@ def test_types_stack(gdb_arrow):
check_stack_repr(gdb_arrow, "duration_type_ns",
"arrow::duration(arrow::TimeUnit::NANO)")
+ check_stack_repr(gdb_arrow, "decimal32_type",
+ "arrow::decimal32(8, 3)")
+ check_stack_repr(gdb_arrow, "decimal64_type",
+ "arrow::decimal64(16, 5)")
check_stack_repr(gdb_arrow, "decimal128_type",
"arrow::decimal128(16, 5)")
check_stack_repr(gdb_arrow, "decimal256_type",
@@ -425,6 +455,10 @@ def test_types_heap(gdb_arrow):
gdb_arrow, "heap_timestamp_type_ns_timezone",
'arrow::timestamp(arrow::TimeUnit::NANO, "Europe/Paris")')
+ check_heap_repr(gdb_arrow, "heap_decimal32_type",
+ "arrow::decimal32(8, 3)")
+ check_heap_repr(gdb_arrow, "heap_decimal64_type",
+ "arrow::decimal64(16, 5)")
check_heap_repr(gdb_arrow, "heap_decimal128_type",
"arrow::decimal128(16, 5)")
@@ -565,6 +599,28 @@ def test_scalars_stack(gdb_arrow):
check_stack_repr(gdb_arrow, "date64_scalar_null",
"arrow::Date64Scalar of null value")
+ check_stack_repr(
+ gdb_arrow, "decimal32_scalar_null",
+ "arrow::Decimal32Scalar of null value [precision=9, scale=4]")
+ check_stack_repr(
+ gdb_arrow, "decimal32_scalar_pos",
+ "arrow::Decimal32Scalar of value 123.4567 [precision=9, scale=4]")
+ check_stack_repr(
+ gdb_arrow, "decimal32_scalar_neg",
+ "arrow::Decimal32Scalar of value -123.4567 [precision=9, scale=4]")
+
+ check_stack_repr(
+ gdb_arrow, "decimal64_scalar_null",
+ "arrow::Decimal64Scalar of null value [precision=18, scale=4]")
+ check_stack_repr(
+ gdb_arrow, "decimal64_scalar_pos",
+ ("arrow::Decimal64Scalar of value 1234567890123.4567 "
+ "[precision=18, scale=4]"))
+ check_stack_repr(
+ gdb_arrow, "decimal64_scalar_neg",
+ ("arrow::Decimal64Scalar of value -1234567890123.4567 "
+ "[precision=18, scale=4]"))
+
check_stack_repr(
gdb_arrow, "decimal128_scalar_null",
"arrow::Decimal128Scalar of null value [precision=10, scale=4]")
@@ -730,6 +786,13 @@ def test_scalars_heap(gdb_arrow):
check_heap_repr(gdb_arrow, "heap_null_scalar", "arrow::NullScalar")
check_heap_repr(gdb_arrow, "heap_bool_scalar",
"arrow::BooleanScalar of value true")
+ check_heap_repr(
+ gdb_arrow, "heap_decimal32_scalar",
+ "arrow::Decimal32Scalar of value 123.4567 [precision=9, scale=4]")
+ check_heap_repr(
+ gdb_arrow, "heap_decimal64_scalar",
+ ("arrow::Decimal64Scalar of value 1234567890123.4567 "
+ "[precision=18, scale=4]"))
check_heap_repr(
gdb_arrow, "heap_decimal128_scalar",
"arrow::Decimal128Scalar of value 123.4567 [precision=10, scale=4]")
@@ -944,6 +1007,17 @@ def test_arrays_heap(gdb_arrow):
"[1] = -2203932303012345679ns [too large to represent]}"))
# Decimal
+ check_heap_repr(
+ gdb_arrow, "heap_decimal32_array",
+ ("arrow::Decimal32Array of type arrow::decimal32(9, 4), "
+ "length 3, offset 0, null count 1 = {"
+ "[0] = null, [1] = -12345.6789, [2] = 12345.6789}"))
+ check_heap_repr(
+ gdb_arrow, "heap_decimal64_array",
+ ("arrow::Decimal64Array of type arrow::decimal64(18, 4), "
+ "length 3, offset 0, null count 1 = {"
+ "[0] = null, [1] = -12345678901234.5678, "
+ "[2] = 12345678901234.5678}"))
check_heap_repr(
gdb_arrow, "heap_decimal128_array",
("arrow::Decimal128Array of type arrow::decimal128(30, 6), "
@@ -956,6 +1030,11 @@ def test_arrays_heap(gdb_arrow):
"length 2, offset 0, null count 1 = {"
"[0] = null, "
"[1] = -123456789012345678901234567890123456789.012345}"))
+ check_heap_repr(
+ gdb_arrow, "heap_decimal32_array_sliced",
+ ("arrow::Decimal32Array of type arrow::decimal32(9, 4), "
+ "length 1, offset 1, unknown null count = {"
+ "[0] = -12345.6789}"))
check_heap_repr(
gdb_arrow, "heap_decimal128_array_sliced",
("arrow::Decimal128Array of type arrow::decimal128(30, 6), "