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

github-merge-queue[bot] 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 16310a9f7b bench(parquet): add FIXED_LEN_BYTE_ARRAY(7) decimal reader 
benchmarks with negative values (#11909)
16310a9f7b is described below

commit 16310a9f7b94463e583dc7b70c812333e2cba75d
Author: Y Ethan Guo <[email protected]>
AuthorDate: Mon Oct 26 20:11:18 2026 +0000

    bench(parquet): add FIXED_LEN_BYTE_ARRAY(7) decimal reader benchmarks with 
negative values (#11909)
    
    # Which issue does this PR close?
    
    - Part of #11908
    
    # Rationale for this change
    
    The `FIXED_LEN_BYTE_ARRAY` decimal benchmarks only cover 16-byte,
    non-negative values, while parquet-mr based writers use the minimal
    width for the precision (7 bytes for `DECIMAL(15,2)`). This adds that
    case ahead of the change for #11908 so it can run on the benchmark
    runner.
    
    # What changes are included in this PR?
    
    Two groups read a `FIXED_LEN_BYTE_ARRAY(7)` `DECIMAL(15,2)` column with
    negative values, as `Decimal128` and, through a type hint, as
    `Decimal64`. The generator now writes the low `type_length` bytes of
    each value, which leaves the existing 16-byte data unchanged.
    
    # Are these changes tested?
    
    They are benchmarks.
    
    # Are there any significant user-facing changes?
    
    No.
    
    AI usage: written with an AI coding assistant under my direction; I
    reviewed the code and ran the benchmarks.
    
    Co-authored-by: Andrew Lamb <[email protected]>
---
 parquet/benches/arrow_reader.rs | 68 +++++++++++++++++++++++++++++++++--------
 1 file changed, 56 insertions(+), 12 deletions(-)

diff --git a/parquet/benches/arrow_reader.rs b/parquet/benches/arrow_reader.rs
index 3b23628009..d7a5a6686d 100644
--- a/parquet/benches/arrow_reader.rs
+++ b/parquet/benches/arrow_reader.rs
@@ -113,6 +113,8 @@ fn build_test_schema() -> SchemaDescPtr {
             }
             REQUIRED BOOLEAN mandatory_bool_leaf;
             OPTIONAL BOOLEAN optional_bool_leaf;
+            REQUIRED FIXED_LEN_BYTE_ARRAY (7) mandatory_decimal5_leaf 
(DECIMAL(15,2));
+            OPTIONAL FIXED_LEN_BYTE_ARRAY (7) optional_decimal5_leaf 
(DECIMAL(15,2));
         }
         ";
     parse_message_type(message_type)
@@ -242,10 +244,9 @@ where
                             big_int.to_signed_bytes_be()
                         }
                         Type::FIXED_LEN_BYTE_ARRAY => {
-                            assert_eq!(column_desc.type_length(), 16);
-                            // fixed length byte array use the fixed size
-                            // the size is 16
-                            value.to_be_bytes().to_vec()
+                            // the low `type_length` bytes of the big-endian 
value
+                            let width = column_desc.type_length() as usize;
+                            value.to_be_bytes()[16 - width..].to_vec()
                         }
                         _ => unimplemented!(),
                     };
@@ -1072,13 +1073,14 @@ fn create_f16_by_bytes_reader(
 fn create_decimal_by_bytes_reader(
     page_iterator: impl PageIterator + 'static,
     column_desc: ColumnDescPtr,
+    arrow_type: Option<DataType>,
 ) -> Box<dyn ArrayReader> {
     let physical_type = column_desc.physical_type();
     match physical_type {
         Type::BYTE_ARRAY => make_byte_array_reader(
             Box::new(page_iterator),
             column_desc,
-            None,
+            arrow_type,
             DEFAULT_BATCH_SIZE,
             None,
         )
@@ -1086,7 +1088,7 @@ fn create_decimal_by_bytes_reader(
         Type::FIXED_LEN_BYTE_ARRAY => make_fixed_len_byte_array_reader(
             Box::new(page_iterator),
             column_desc,
-            None,
+            arrow_type,
             DEFAULT_BATCH_SIZE,
             None,
         )
@@ -1194,6 +1196,7 @@ fn bench_byte_decimal<T>(
     encoding: Encoding,
     min: i128,
     max: i128,
+    arrow_type: Option<DataType>,
 ) where
     T: parquet::data_type::DataType,
     T::T: From<Vec<u8>>,
@@ -1213,8 +1216,11 @@ fn bench_byte_decimal<T>(
         encoding.to_string().to_lowercase() + " encoded, mandatory, no NULLs",
         |b| {
             b.iter(|| {
-                let array_reader =
-                    create_decimal_by_bytes_reader(data.clone(), 
mandatory_column_desc.clone());
+                let array_reader = create_decimal_by_bytes_reader(
+                    data.clone(),
+                    mandatory_column_desc.clone(),
+                    arrow_type.clone(),
+                );
                 count = bench_array_reader(array_reader);
             });
             assert_eq!(count, EXPECTED_VALUE_COUNT);
@@ -1232,8 +1238,11 @@ fn bench_byte_decimal<T>(
         encoding.to_string().to_lowercase() + " encoded, optional, no NULLs",
         |b| {
             b.iter(|| {
-                let array_reader =
-                    create_decimal_by_bytes_reader(data.clone(), 
optional_column_desc.clone());
+                let array_reader = create_decimal_by_bytes_reader(
+                    data.clone(),
+                    optional_column_desc.clone(),
+                    arrow_type.clone(),
+                );
                 count = bench_array_reader(array_reader);
             });
             assert_eq!(count, EXPECTED_VALUE_COUNT);
@@ -1252,8 +1261,11 @@ fn bench_byte_decimal<T>(
         encoding.to_string().to_lowercase() + " encoded, optional, half NULLs",
         |b| {
             b.iter(|| {
-                let array_reader =
-                    create_decimal_by_bytes_reader(data.clone(), 
optional_column_desc.clone());
+                let array_reader = create_decimal_by_bytes_reader(
+                    data.clone(),
+                    optional_column_desc.clone(),
+                    arrow_type.clone(),
+                );
                 count = bench_array_reader(array_reader);
             });
             assert_eq!(count, EXPECTED_VALUE_COUNT);
@@ -1961,6 +1973,7 @@ fn decimal_benches(c: &mut Criterion) {
         // precision is 16: the max is 9999999999999999
         9999999999999000,
         9999999999999999,
+        None,
     );
     group.finish();
 
@@ -1976,6 +1989,7 @@ fn decimal_benches(c: &mut Criterion) {
         // precision is 16: the max is 9999999999999999
         9999999999999000,
         9999999999999999,
+        None,
     );
     group.finish();
 
@@ -1990,6 +2004,36 @@ fn decimal_benches(c: &mut Criterion) {
         // precision is 16: the max is 9999999999999999
         9999999999999000,
         9999999999999999,
+        None,
+    );
+    group.finish();
+
+    // parquet FIXED_LEN_BYTE_ARRAY(7), logical type decimal(15,2): the minimal
+    // width, as Spark's legacy format writes it
+    let mut group = 
c.benchmark_group("arrow_array_reader/FIXED_LEN_BYTE_ARRAY(7)/Decimal128Array");
+    let mandatory_decimal5_leaf_desc = schema.column(45);
+    let optional_decimal5_leaf_desc = schema.column(46);
+    bench_byte_decimal::<FixedLenByteArrayType>(
+        &mut group,
+        &mandatory_decimal5_leaf_desc,
+        &optional_decimal5_leaf_desc,
+        Encoding::PLAIN,
+        // precision is 15, with negative values to exercise sign extension
+        -999999999999999,
+        999999999999999,
+        None,
+    );
+    group.finish();
+
+    let mut group = 
c.benchmark_group("arrow_array_reader/FIXED_LEN_BYTE_ARRAY(7)/Decimal64Array");
+    bench_byte_decimal::<FixedLenByteArrayType>(
+        &mut group,
+        &mandatory_decimal5_leaf_desc,
+        &optional_decimal5_leaf_desc,
+        Encoding::PLAIN,
+        -999999999999999,
+        999999999999999,
+        Some(DataType::Decimal64(15, 2)),
     );
     group.finish();
 }

Reply via email to