This is an automated email from the ASF dual-hosted git repository. github-merge-queue[bot] pushed a commit to branch gh-readonly-queue/main/pr-11544-497bd538e8886246a7002b941ed305b9b870f10c in repository https://gitbox.apache.org/repos/asf/arrow-rs.git
commit 7d04f36df412ac6177fa2fc768e8215089899581 Author: Shawn Chang <[email protected]> AuthorDate: Thu Oct 15 03:55:07 2026 +0000 fix(parquet): Fix physical type for precision-one decimals (#11544) # Which issue does this PR close? No linked issue. # Rationale for this change Decimal precision 1 was incorrectly mapped to Parquet INT64 because the INT32 physical-type range used an exclusive lower bound, even though precisions 1 through 9 fit in INT32. This corrects the generated Parquet physical schema so a precision-one decimal is written as INT32. # What changes are included in this PR? A one-line boundary correction in the Arrow-to-Parquet decimal mapping (exclusive `> 1` lower bound changed to inclusive `>= 1`), plus a regression test generalized into a table-driven test. # Are these changes tested? Yes. The table-driven regression test covers all three decimal physical-type branches and their boundaries: INT32 for precisions 1–9, INT64 for precisions 10–18, and FIXED_LEN_BYTE_ARRAY for precisions greater than 18. # Are there any significant user-facing changes? No significant API or compatibility changes. This corrects the generated Parquet physical schema for precision-one decimals. --- parquet/src/arrow/schema/mod.rs | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/parquet/src/arrow/schema/mod.rs b/parquet/src/arrow/schema/mod.rs index 4189c3ab0f..968571cbb6 100644 --- a/parquet/src/arrow/schema/mod.rs +++ b/parquet/src/arrow/schema/mod.rs @@ -744,7 +744,7 @@ fn arrow_to_parquet_type(field: &Field, coerce_types: bool) -> Result<Type> { | DataType::Decimal256(precision, scale) => { // Decimal precision determines the Parquet physical type to use. // Following the: https://github.com/apache/parquet-format/blob/master/LogicalTypes.md#decimal - let (physical_type, length) = if *precision > 1 && *precision <= 9 { + let (physical_type, length) = if *precision >= 1 && *precision <= 9 { (PhysicalType::INT32, -1) } else if *precision <= 18 { (PhysicalType::INT64, -1) @@ -977,6 +977,41 @@ mod tests { assert_eq!(&arrow_fields, converted_arrow_schema.fields()); } + #[test] + fn test_decimal_precision_physical_types() { + let cases = [ + (1, PhysicalType::INT32, None), + (9, PhysicalType::INT32, None), + (10, PhysicalType::INT64, None), + (18, PhysicalType::INT64, None), + (19, PhysicalType::FIXED_LEN_BYTE_ARRAY, Some(9)), + (38, PhysicalType::FIXED_LEN_BYTE_ARRAY, Some(16)), + ]; + + for (precision, expected_type, expected_length) in cases { + let arrow_schema = Schema::new(vec![Field::new( + "decimal", + DataType::Decimal128(precision, 0), + false, + )]); + let parquet_schema = ArrowSchemaConverter::new().convert(&arrow_schema).unwrap(); + let column = parquet_schema.column(0); + + assert_eq!( + column.physical_type(), + expected_type, + "precision {precision}" + ); + if let Some(expected_length) = expected_length { + assert_eq!( + column.type_length(), + expected_length, + "precision {precision}" + ); + } + } + } + #[test] fn test_byte_array_fields() { let message_type = "
