This is an automated email from the ASF dual-hosted git repository.
curth 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 1081d018e3 Refactor some decimal-related code and tests (#7062)
1081d018e3 is described below
commit 1081d018e3714b613d2710848507032db446ebe1
Author: Curt Hagenlocher <[email protected]>
AuthorDate: Fri Feb 7 18:03:02 2025 -0800
Refactor some decimal-related code and tests (#7062)
* Refactor some decimal-related code and tests in preparation for adding
Decimal32 and Decimal64 support
* Fixed symbol
* Apply PR feedback
* Fixed format problem
* Fixed logical merge conflicts
* PR feedback
---
arrow-cast/src/cast/decimal.rs | 75 ++---
arrow-cast/src/cast/dictionary.rs | 88 ++---
arrow-cast/src/cast/mod.rs | 578 +++++++++++++--------------------
arrow-data/src/data.rs | 6 +-
arrow-integration-test/src/datatype.rs | 12 +-
arrow-ipc/src/convert.rs | 18 +-
arrow-ord/src/sort.rs | 294 +++++------------
arrow-schema/src/ffi.rs | 11 +-
arrow/benches/builder.rs | 2 +-
arrow/tests/array_cast.rs | 4 +-
10 files changed, 400 insertions(+), 688 deletions(-)
diff --git a/arrow-cast/src/cast/decimal.rs b/arrow-cast/src/cast/decimal.rs
index fee9c007c0..e47852a5e3 100644
--- a/arrow-cast/src/cast/decimal.rs
+++ b/arrow-cast/src/cast/decimal.rs
@@ -25,6 +25,8 @@ pub(crate) trait DecimalCast: Sized {
fn to_i256(self) -> Option<i256>;
fn from_decimal<T: DecimalCast>(n: T) -> Option<Self>;
+
+ fn from_f64(n: f64) -> Option<Self>;
}
impl DecimalCast for i128 {
@@ -39,6 +41,10 @@ impl DecimalCast for i128 {
fn from_decimal<T: DecimalCast>(n: T) -> Option<Self> {
n.to_i128()
}
+
+ fn from_f64(n: f64) -> Option<Self> {
+ n.to_i128()
+ }
}
impl DecimalCast for i256 {
@@ -53,6 +59,10 @@ impl DecimalCast for i256 {
fn from_decimal<T: DecimalCast>(n: T) -> Option<Self> {
n.to_i256()
}
+
+ fn from_f64(n: f64) -> Option<Self> {
+ i256::from_f64(n)
+ }
}
pub(crate) fn cast_decimal_to_decimal_error<I, O>(
@@ -463,52 +473,7 @@ where
Ok(Arc::new(result))
}
-pub(crate) fn cast_floating_point_to_decimal128<T: ArrowPrimitiveType>(
- array: &PrimitiveArray<T>,
- precision: u8,
- scale: i8,
- cast_options: &CastOptions,
-) -> Result<ArrayRef, ArrowError>
-where
- <T as ArrowPrimitiveType>::Native: AsPrimitive<f64>,
-{
- let mul = 10_f64.powi(scale as i32);
-
- if cast_options.safe {
- array
- .unary_opt::<_, Decimal128Type>(|v| {
- (mul * v.as_())
- .round()
- .to_i128()
- .filter(|v| Decimal128Type::is_valid_decimal_precision(*v,
precision))
- })
- .with_precision_and_scale(precision, scale)
- .map(|a| Arc::new(a) as ArrayRef)
- } else {
- array
- .try_unary::<_, Decimal128Type, _>(|v| {
- (mul * v.as_())
- .round()
- .to_i128()
- .ok_or_else(|| {
- ArrowError::CastError(format!(
- "Cannot cast to {}({}, {}). Overflowing on {:?}",
- Decimal128Type::PREFIX,
- precision,
- scale,
- v
- ))
- })
- .and_then(|v| {
- Decimal128Type::validate_decimal_precision(v,
precision).map(|_| v)
- })
- })?
- .with_precision_and_scale(precision, scale)
- .map(|a| Arc::new(a) as ArrayRef)
- }
-}
-
-pub(crate) fn cast_floating_point_to_decimal256<T: ArrowPrimitiveType>(
+pub(crate) fn cast_floating_point_to_decimal<T: ArrowPrimitiveType, D>(
array: &PrimitiveArray<T>,
precision: u8,
scale: i8,
@@ -516,33 +481,33 @@ pub(crate) fn cast_floating_point_to_decimal256<T:
ArrowPrimitiveType>(
) -> Result<ArrayRef, ArrowError>
where
<T as ArrowPrimitiveType>::Native: AsPrimitive<f64>,
+ D: DecimalType + ArrowPrimitiveType,
+ <D as ArrowPrimitiveType>::Native: DecimalCast,
{
let mul = 10_f64.powi(scale as i32);
if cast_options.safe {
array
- .unary_opt::<_, Decimal256Type>(|v| {
- i256::from_f64((v.as_() * mul).round())
- .filter(|v| Decimal256Type::is_valid_decimal_precision(*v,
precision))
+ .unary_opt::<_, D>(|v| {
+ D::Native::from_f64((mul * v.as_()).round())
+ .filter(|v| D::is_valid_decimal_precision(*v, precision))
})
.with_precision_and_scale(precision, scale)
.map(|a| Arc::new(a) as ArrayRef)
} else {
array
- .try_unary::<_, Decimal256Type, _>(|v| {
- i256::from_f64((v.as_() * mul).round())
+ .try_unary::<_, D, _>(|v| {
+ D::Native::from_f64((mul * v.as_()).round())
.ok_or_else(|| {
ArrowError::CastError(format!(
"Cannot cast to {}({}, {}). Overflowing on {:?}",
- Decimal256Type::PREFIX,
+ D::PREFIX,
precision,
scale,
v
))
})
- .and_then(|v| {
- Decimal256Type::validate_decimal_precision(v,
precision).map(|_| v)
- })
+ .and_then(|v| D::validate_decimal_precision(v,
precision).map(|_| v))
})?
.with_precision_and_scale(precision, scale)
.map(|a| Arc::new(a) as ArrayRef)
diff --git a/arrow-cast/src/cast/dictionary.rs
b/arrow-cast/src/cast/dictionary.rs
index ec0ab346f9..fd3be26159 100644
--- a/arrow-cast/src/cast/dictionary.rs
+++ b/arrow-cast/src/cast/dictionary.rs
@@ -214,50 +214,20 @@ pub(crate) fn cast_to_dictionary<K:
ArrowDictionaryKeyType>(
UInt16 => pack_numeric_to_dictionary::<K, UInt16Type>(array,
dict_value_type, cast_options),
UInt32 => pack_numeric_to_dictionary::<K, UInt32Type>(array,
dict_value_type, cast_options),
UInt64 => pack_numeric_to_dictionary::<K, UInt64Type>(array,
dict_value_type, cast_options),
- Decimal128(p, s) => {
- let dict = pack_numeric_to_dictionary::<K, Decimal128Type>(
- array,
- dict_value_type,
- cast_options,
- )?;
- let dict = dict
- .as_dictionary::<K>()
- .downcast_dict::<Decimal128Array>()
- .ok_or_else(|| {
- ArrowError::ComputeError(
- "Internal Error: Cannot cast dict to
Decimal128Array".to_string(),
- )
- })?;
- let value = dict.values().clone();
- // Set correct precision/scale
- let value = value.with_precision_and_scale(p, s)?;
- Ok(Arc::new(DictionaryArray::<K>::try_new(
- dict.keys().clone(),
- Arc::new(value),
- )?))
- }
- Decimal256(p, s) => {
- let dict = pack_numeric_to_dictionary::<K, Decimal256Type>(
- array,
- dict_value_type,
- cast_options,
- )?;
- let dict = dict
- .as_dictionary::<K>()
- .downcast_dict::<Decimal256Array>()
- .ok_or_else(|| {
- ArrowError::ComputeError(
- "Internal Error: Cannot cast dict to
Decimal256Array".to_string(),
- )
- })?;
- let value = dict.values().clone();
- // Set correct precision/scale
- let value = value.with_precision_and_scale(p, s)?;
- Ok(Arc::new(DictionaryArray::<K>::try_new(
- dict.keys().clone(),
- Arc::new(value),
- )?))
- }
+ Decimal128(p, s) => pack_decimal_to_dictionary::<K, Decimal128Type>(
+ array,
+ dict_value_type,
+ p,
+ s,
+ cast_options,
+ ),
+ Decimal256(p, s) => pack_decimal_to_dictionary::<K, Decimal256Type>(
+ array,
+ dict_value_type,
+ p,
+ s,
+ cast_options,
+ ),
Float16 => {
pack_numeric_to_dictionary::<K, Float16Type>(array,
dict_value_type, cast_options)
}
@@ -359,6 +329,36 @@ where
Ok(Arc::new(b.finish()))
}
+pub(crate) fn pack_decimal_to_dictionary<K, D>(
+ array: &dyn Array,
+ dict_value_type: &DataType,
+ precision: u8,
+ scale: i8,
+ cast_options: &CastOptions,
+) -> Result<ArrayRef, ArrowError>
+where
+ K: ArrowDictionaryKeyType,
+ D: DecimalType + ArrowPrimitiveType,
+{
+ let dict = pack_numeric_to_dictionary::<K, D>(array, dict_value_type,
cast_options)?;
+ let dict = dict
+ .as_dictionary::<K>()
+ .downcast_dict::<PrimitiveArray<D>>()
+ .ok_or_else(|| {
+ ArrowError::ComputeError(format!(
+ "Internal Error: Cannot cast dict to {}Array",
+ D::PREFIX
+ ))
+ })?;
+ let value = dict.values().clone();
+ // Set correct precision/scale
+ let value = value.with_precision_and_scale(precision, scale)?;
+ Ok(Arc::new(DictionaryArray::<K>::try_new(
+ dict.keys().clone(),
+ Arc::new(value),
+ )?))
+}
+
pub(crate) fn string_view_to_dictionary<K, O: OffsetSizeTrait>(
array: &dyn Array,
) -> Result<ArrayRef, ArrowError>
diff --git a/arrow-cast/src/cast/mod.rs b/arrow-cast/src/cast/mod.rs
index c448ad9601..53069c1a16 100644
--- a/arrow-cast/src/cast/mod.rs
+++ b/arrow-cast/src/cast/mod.rs
@@ -234,7 +234,7 @@ pub fn can_cast_types(from_type: &DataType, to_type:
&DataType) -> bool {
| BinaryView,
) => true,
(Utf8 | LargeUtf8, Utf8View) => true,
- (BinaryView, Binary | LargeBinary | Utf8 | LargeUtf8 | Utf8View ) =>
true,
+ (BinaryView, Binary | LargeBinary | Utf8 | LargeUtf8 | Utf8View) =>
true,
(Utf8View | Utf8 | LargeUtf8, _) => to_type.is_numeric() && to_type !=
&Float16,
(_, Utf8 | LargeUtf8) => from_type.is_primitive(),
(_, Utf8View) => from_type.is_numeric(),
@@ -830,6 +830,7 @@ pub fn cast_with_options(
(Map(_, ordered1), Map(_, ordered2)) if ordered1 == ordered2 => {
cast_map_values(array.as_map(), to_type, cast_options,
ordered1.to_owned())
}
+ // Decimal to decimal, same width
(Decimal128(p1, s1), Decimal128(p2, s2)) => {
cast_decimal_to_decimal_same_type::<Decimal128Type>(
array.as_primitive(),
@@ -850,6 +851,7 @@ pub fn cast_with_options(
cast_options,
)
}
+ // Decimal to decimal, different width
(Decimal128(_, s1), Decimal256(p2, s2)) => {
cast_decimal_to_decimal::<Decimal128Type, Decimal256Type>(
array.as_primitive(),
@@ -868,315 +870,51 @@ pub fn cast_with_options(
cast_options,
)
}
+ // Decimal to non-decimal
(Decimal128(_, scale), _) if !to_type.is_temporal() => {
- // cast decimal to other type
- match to_type {
- UInt8 => cast_decimal_to_integer::<Decimal128Type, UInt8Type>(
- array,
- 10_i128,
- *scale,
- cast_options,
- ),
- UInt16 => cast_decimal_to_integer::<Decimal128Type,
UInt16Type>(
- array,
- 10_i128,
- *scale,
- cast_options,
- ),
- UInt32 => cast_decimal_to_integer::<Decimal128Type,
UInt32Type>(
- array,
- 10_i128,
- *scale,
- cast_options,
- ),
- UInt64 => cast_decimal_to_integer::<Decimal128Type,
UInt64Type>(
- array,
- 10_i128,
- *scale,
- cast_options,
- ),
- Int8 => cast_decimal_to_integer::<Decimal128Type, Int8Type>(
- array,
- 10_i128,
- *scale,
- cast_options,
- ),
- Int16 => cast_decimal_to_integer::<Decimal128Type, Int16Type>(
- array,
- 10_i128,
- *scale,
- cast_options,
- ),
- Int32 => cast_decimal_to_integer::<Decimal128Type, Int32Type>(
- array,
- 10_i128,
- *scale,
- cast_options,
- ),
- Int64 => cast_decimal_to_integer::<Decimal128Type, Int64Type>(
- array,
- 10_i128,
- *scale,
- cast_options,
- ),
- Float32 => cast_decimal_to_float::<Decimal128Type,
Float32Type, _>(array, |x| {
- (x as f64 / 10_f64.powi(*scale as i32)) as f32
- }),
- Float64 => cast_decimal_to_float::<Decimal128Type,
Float64Type, _>(array, |x| {
- x as f64 / 10_f64.powi(*scale as i32)
- }),
- Utf8View => value_to_string_view(array, cast_options),
- Utf8 => value_to_string::<i32>(array, cast_options),
- LargeUtf8 => value_to_string::<i64>(array, cast_options),
- Null => Ok(new_null_array(to_type, array.len())),
- _ => Err(ArrowError::CastError(format!(
- "Casting from {from_type:?} to {to_type:?} not supported"
- ))),
- }
+ cast_from_decimal::<Decimal128Type, _>(
+ array,
+ 10_i128,
+ scale,
+ from_type,
+ to_type,
+ |x: i128| x as f64,
+ cast_options,
+ )
}
(Decimal256(_, scale), _) if !to_type.is_temporal() => {
- // cast decimal to other type
- match to_type {
- UInt8 => cast_decimal_to_integer::<Decimal256Type, UInt8Type>(
- array,
- i256::from_i128(10_i128),
- *scale,
- cast_options,
- ),
- UInt16 => cast_decimal_to_integer::<Decimal256Type,
UInt16Type>(
- array,
- i256::from_i128(10_i128),
- *scale,
- cast_options,
- ),
- UInt32 => cast_decimal_to_integer::<Decimal256Type,
UInt32Type>(
- array,
- i256::from_i128(10_i128),
- *scale,
- cast_options,
- ),
- UInt64 => cast_decimal_to_integer::<Decimal256Type,
UInt64Type>(
- array,
- i256::from_i128(10_i128),
- *scale,
- cast_options,
- ),
- Int8 => cast_decimal_to_integer::<Decimal256Type, Int8Type>(
- array,
- i256::from_i128(10_i128),
- *scale,
- cast_options,
- ),
- Int16 => cast_decimal_to_integer::<Decimal256Type, Int16Type>(
- array,
- i256::from_i128(10_i128),
- *scale,
- cast_options,
- ),
- Int32 => cast_decimal_to_integer::<Decimal256Type, Int32Type>(
- array,
- i256::from_i128(10_i128),
- *scale,
- cast_options,
- ),
- Int64 => cast_decimal_to_integer::<Decimal256Type, Int64Type>(
- array,
- i256::from_i128(10_i128),
- *scale,
- cast_options,
- ),
- Float32 => cast_decimal_to_float::<Decimal256Type,
Float32Type, _>(array, |x| {
- (x.to_f64().unwrap() / 10_f64.powi(*scale as i32)) as f32
- }),
- Float64 => cast_decimal_to_float::<Decimal256Type,
Float64Type, _>(array, |x| {
- x.to_f64().unwrap() / 10_f64.powi(*scale as i32)
- }),
- Utf8View => value_to_string_view(array, cast_options),
- Utf8 => value_to_string::<i32>(array, cast_options),
- LargeUtf8 => value_to_string::<i64>(array, cast_options),
- Null => Ok(new_null_array(to_type, array.len())),
- _ => Err(ArrowError::CastError(format!(
- "Casting from {from_type:?} to {to_type:?} not supported"
- ))),
- }
+ cast_from_decimal::<Decimal256Type, _>(
+ array,
+ i256::from_i128(10_i128),
+ scale,
+ from_type,
+ to_type,
+ |x: i256| x.to_f64().unwrap(),
+ cast_options,
+ )
}
+ // Non-decimal to decimal
(_, Decimal128(precision, scale)) if !from_type.is_temporal() => {
- // cast data to decimal
- match from_type {
- UInt8 => cast_integer_to_decimal::<_, Decimal128Type, _>(
- array.as_primitive::<UInt8Type>(),
- *precision,
- *scale,
- 10_i128,
- cast_options,
- ),
- UInt16 => cast_integer_to_decimal::<_, Decimal128Type, _>(
- array.as_primitive::<UInt16Type>(),
- *precision,
- *scale,
- 10_i128,
- cast_options,
- ),
- UInt32 => cast_integer_to_decimal::<_, Decimal128Type, _>(
- array.as_primitive::<UInt32Type>(),
- *precision,
- *scale,
- 10_i128,
- cast_options,
- ),
- UInt64 => cast_integer_to_decimal::<_, Decimal128Type, _>(
- array.as_primitive::<UInt64Type>(),
- *precision,
- *scale,
- 10_i128,
- cast_options,
- ),
- Int8 => cast_integer_to_decimal::<_, Decimal128Type, _>(
- array.as_primitive::<Int8Type>(),
- *precision,
- *scale,
- 10_i128,
- cast_options,
- ),
- Int16 => cast_integer_to_decimal::<_, Decimal128Type, _>(
- array.as_primitive::<Int16Type>(),
- *precision,
- *scale,
- 10_i128,
- cast_options,
- ),
- Int32 => cast_integer_to_decimal::<_, Decimal128Type, _>(
- array.as_primitive::<Int32Type>(),
- *precision,
- *scale,
- 10_i128,
- cast_options,
- ),
- Int64 => cast_integer_to_decimal::<_, Decimal128Type, _>(
- array.as_primitive::<Int64Type>(),
- *precision,
- *scale,
- 10_i128,
- cast_options,
- ),
- Float32 => cast_floating_point_to_decimal128(
- array.as_primitive::<Float32Type>(),
- *precision,
- *scale,
- cast_options,
- ),
- Float64 => cast_floating_point_to_decimal128(
- array.as_primitive::<Float64Type>(),
- *precision,
- *scale,
- cast_options,
- ),
- Utf8View | Utf8 => cast_string_to_decimal::<Decimal128Type,
i32>(
- array,
- *precision,
- *scale,
- cast_options,
- ),
- LargeUtf8 => cast_string_to_decimal::<Decimal128Type, i64>(
- array,
- *precision,
- *scale,
- cast_options,
- ),
- Null => Ok(new_null_array(to_type, array.len())),
- _ => Err(ArrowError::CastError(format!(
- "Casting from {from_type:?} to {to_type:?} not supported"
- ))),
- }
+ cast_to_decimal::<Decimal128Type, _>(
+ array,
+ 10_i128,
+ precision,
+ scale,
+ from_type,
+ to_type,
+ cast_options,
+ )
}
(_, Decimal256(precision, scale)) if !from_type.is_temporal() => {
- // cast data to decimal
- match from_type {
- UInt8 => cast_integer_to_decimal::<_, Decimal256Type, _>(
- array.as_primitive::<UInt8Type>(),
- *precision,
- *scale,
- i256::from_i128(10_i128),
- cast_options,
- ),
- UInt16 => cast_integer_to_decimal::<_, Decimal256Type, _>(
- array.as_primitive::<UInt16Type>(),
- *precision,
- *scale,
- i256::from_i128(10_i128),
- cast_options,
- ),
- UInt32 => cast_integer_to_decimal::<_, Decimal256Type, _>(
- array.as_primitive::<UInt32Type>(),
- *precision,
- *scale,
- i256::from_i128(10_i128),
- cast_options,
- ),
- UInt64 => cast_integer_to_decimal::<_, Decimal256Type, _>(
- array.as_primitive::<UInt64Type>(),
- *precision,
- *scale,
- i256::from_i128(10_i128),
- cast_options,
- ),
- Int8 => cast_integer_to_decimal::<_, Decimal256Type, _>(
- array.as_primitive::<Int8Type>(),
- *precision,
- *scale,
- i256::from_i128(10_i128),
- cast_options,
- ),
- Int16 => cast_integer_to_decimal::<_, Decimal256Type, _>(
- array.as_primitive::<Int16Type>(),
- *precision,
- *scale,
- i256::from_i128(10_i128),
- cast_options,
- ),
- Int32 => cast_integer_to_decimal::<_, Decimal256Type, _>(
- array.as_primitive::<Int32Type>(),
- *precision,
- *scale,
- i256::from_i128(10_i128),
- cast_options,
- ),
- Int64 => cast_integer_to_decimal::<_, Decimal256Type, _>(
- array.as_primitive::<Int64Type>(),
- *precision,
- *scale,
- i256::from_i128(10_i128),
- cast_options,
- ),
- Float32 => cast_floating_point_to_decimal256(
- array.as_primitive::<Float32Type>(),
- *precision,
- *scale,
- cast_options,
- ),
- Float64 => cast_floating_point_to_decimal256(
- array.as_primitive::<Float64Type>(),
- *precision,
- *scale,
- cast_options,
- ),
- Utf8View | Utf8 => cast_string_to_decimal::<Decimal256Type,
i32>(
- array,
- *precision,
- *scale,
- cast_options,
- ),
- LargeUtf8 => cast_string_to_decimal::<Decimal256Type, i64>(
- array,
- *precision,
- *scale,
- cast_options,
- ),
- Null => Ok(new_null_array(to_type, array.len())),
- _ => Err(ArrowError::CastError(format!(
- "Casting from {from_type:?} to {to_type:?} not supported"
- ))),
- }
+ cast_to_decimal::<Decimal256Type, _>(
+ array,
+ i256::from_i128(10_i128),
+ precision,
+ scale,
+ from_type,
+ to_type,
+ cast_options,
+ )
}
(Struct(_), Struct(to_fields)) => {
let array = array.as_struct();
@@ -2192,6 +1930,150 @@ pub fn cast_with_options(
}
}
+fn cast_from_decimal<D, F>(
+ array: &dyn Array,
+ base: D::Native,
+ scale: &i8,
+ from_type: &DataType,
+ to_type: &DataType,
+ as_float: F,
+ cast_options: &CastOptions,
+) -> Result<ArrayRef, ArrowError>
+where
+ D: DecimalType + ArrowPrimitiveType,
+ <D as ArrowPrimitiveType>::Native: ArrowNativeTypeOp + ToPrimitive,
+ F: Fn(D::Native) -> f64,
+{
+ use DataType::*;
+ // cast decimal to other type
+ match to_type {
+ UInt8 => cast_decimal_to_integer::<D, UInt8Type>(array, base, *scale,
cast_options),
+ UInt16 => cast_decimal_to_integer::<D, UInt16Type>(array, base,
*scale, cast_options),
+ UInt32 => cast_decimal_to_integer::<D, UInt32Type>(array, base,
*scale, cast_options),
+ UInt64 => cast_decimal_to_integer::<D, UInt64Type>(array, base,
*scale, cast_options),
+ Int8 => cast_decimal_to_integer::<D, Int8Type>(array, base, *scale,
cast_options),
+ Int16 => cast_decimal_to_integer::<D, Int16Type>(array, base, *scale,
cast_options),
+ Int32 => cast_decimal_to_integer::<D, Int32Type>(array, base, *scale,
cast_options),
+ Int64 => cast_decimal_to_integer::<D, Int64Type>(array, base, *scale,
cast_options),
+ Float32 => cast_decimal_to_float::<D, Float32Type, _>(array, |x| {
+ (as_float(x) / 10_f64.powi(*scale as i32)) as f32
+ }),
+ Float64 => cast_decimal_to_float::<D, Float64Type, _>(array, |x| {
+ as_float(x) / 10_f64.powi(*scale as i32)
+ }),
+ Utf8View => value_to_string_view(array, cast_options),
+ Utf8 => value_to_string::<i32>(array, cast_options),
+ LargeUtf8 => value_to_string::<i64>(array, cast_options),
+ Null => Ok(new_null_array(to_type, array.len())),
+ _ => Err(ArrowError::CastError(format!(
+ "Casting from {from_type:?} to {to_type:?} not supported"
+ ))),
+ }
+}
+
+fn cast_to_decimal<D, M>(
+ array: &dyn Array,
+ base: M,
+ precision: &u8,
+ scale: &i8,
+ from_type: &DataType,
+ to_type: &DataType,
+ cast_options: &CastOptions,
+) -> Result<ArrayRef, ArrowError>
+where
+ D: DecimalType + ArrowPrimitiveType<Native = M>,
+ M: ArrowNativeTypeOp + DecimalCast,
+ u8: num::traits::AsPrimitive<M>,
+ u16: num::traits::AsPrimitive<M>,
+ u32: num::traits::AsPrimitive<M>,
+ u64: num::traits::AsPrimitive<M>,
+ i8: num::traits::AsPrimitive<M>,
+ i16: num::traits::AsPrimitive<M>,
+ i32: num::traits::AsPrimitive<M>,
+ i64: num::traits::AsPrimitive<M>,
+{
+ use DataType::*;
+ // cast data to decimal
+ match from_type {
+ UInt8 => cast_integer_to_decimal::<_, D, M>(
+ array.as_primitive::<UInt8Type>(),
+ *precision,
+ *scale,
+ base,
+ cast_options,
+ ),
+ UInt16 => cast_integer_to_decimal::<_, D, _>(
+ array.as_primitive::<UInt16Type>(),
+ *precision,
+ *scale,
+ base,
+ cast_options,
+ ),
+ UInt32 => cast_integer_to_decimal::<_, D, _>(
+ array.as_primitive::<UInt32Type>(),
+ *precision,
+ *scale,
+ base,
+ cast_options,
+ ),
+ UInt64 => cast_integer_to_decimal::<_, D, _>(
+ array.as_primitive::<UInt64Type>(),
+ *precision,
+ *scale,
+ base,
+ cast_options,
+ ),
+ Int8 => cast_integer_to_decimal::<_, D, _>(
+ array.as_primitive::<Int8Type>(),
+ *precision,
+ *scale,
+ base,
+ cast_options,
+ ),
+ Int16 => cast_integer_to_decimal::<_, D, _>(
+ array.as_primitive::<Int16Type>(),
+ *precision,
+ *scale,
+ base,
+ cast_options,
+ ),
+ Int32 => cast_integer_to_decimal::<_, D, _>(
+ array.as_primitive::<Int32Type>(),
+ *precision,
+ *scale,
+ base,
+ cast_options,
+ ),
+ Int64 => cast_integer_to_decimal::<_, D, _>(
+ array.as_primitive::<Int64Type>(),
+ *precision,
+ *scale,
+ base,
+ cast_options,
+ ),
+ Float32 => cast_floating_point_to_decimal::<_, D>(
+ array.as_primitive::<Float32Type>(),
+ *precision,
+ *scale,
+ cast_options,
+ ),
+ Float64 => cast_floating_point_to_decimal::<_, D>(
+ array.as_primitive::<Float64Type>(),
+ *precision,
+ *scale,
+ cast_options,
+ ),
+ Utf8View | Utf8 => {
+ cast_string_to_decimal::<D, i32>(array, *precision, *scale,
cast_options)
+ }
+ LargeUtf8 => cast_string_to_decimal::<D, i64>(array, *precision,
*scale, cast_options),
+ Null => Ok(new_null_array(to_type, array.len())),
+ _ => Err(ArrowError::CastError(format!(
+ "Casting from {from_type:?} to {to_type:?} not supported"
+ ))),
+ }
+}
+
/// Get the time unit as a multiple of a second
const fn time_unit_multiple(unit: &TimeUnit) -> i64 {
match unit {
@@ -2527,7 +2409,7 @@ mod tests {
};
}
- fn create_decimal_array(
+ fn create_decimal128_array(
array: Vec<Option<i128>>,
precision: u8,
scale: i8,
@@ -2596,7 +2478,7 @@ mod tests {
Some(-3123456),
None,
];
- let array = create_decimal_array(array, 20, 4).unwrap();
+ let array = create_decimal128_array(array, 20, 4).unwrap();
// decimal128 to decimal128
let input_type = DataType::Decimal128(20, 4);
let output_type = DataType::Decimal128(20, 3);
@@ -2681,7 +2563,7 @@ mod tests {
let output_type = DataType::Decimal128(20, 4);
assert!(can_cast_types(&input_type, &output_type));
let array = vec![Some(1123456), Some(2123456), Some(3123456), None];
- let array = create_decimal_array(array, 20, 3).unwrap();
+ let array = create_decimal128_array(array, 20, 3).unwrap();
generate_cast_test_case!(
&array,
Decimal128Array,
@@ -2695,7 +2577,7 @@ mod tests {
);
// negative test
let array = vec![Some(123456), None];
- let array = create_decimal_array(array, 10, 0).unwrap();
+ let array = create_decimal128_array(array, 10, 0).unwrap();
let result_safe = cast(&array, &DataType::Decimal128(2, 2));
assert!(result_safe.is_ok());
let options = CastOptions {
@@ -2719,7 +2601,7 @@ mod tests {
);
assert!(can_cast_types(&input_type, &output_type));
let array = vec![Some(1123456), Some(2123456), Some(3123456), None];
- let array = create_decimal_array(array, p, s).unwrap();
+ let array = create_decimal128_array(array, p, s).unwrap();
let cast_array = cast_with_options(&array, &output_type,
&CastOptions::default()).unwrap();
assert_eq!(cast_array.data_type(), &output_type);
}
@@ -2735,7 +2617,7 @@ mod tests {
);
assert!(can_cast_types(&input_type, &output_type));
let array = vec![Some(1123456), Some(2123456), Some(3123456), None];
- let array = create_decimal_array(array, p, s).unwrap();
+ let array = create_decimal128_array(array, p, s).unwrap();
let cast_array = cast_with_options(&array, &output_type,
&CastOptions::default()).unwrap();
assert_eq!(cast_array.data_type(), &output_type);
}
@@ -2747,7 +2629,7 @@ mod tests {
assert!(can_cast_types(&input_type, &output_type));
let array = vec![Some(i128::MAX)];
- let array = create_decimal_array(array, 38, 3).unwrap();
+ let array = create_decimal128_array(array, 38, 3).unwrap();
let result = cast_with_options(
&array,
&output_type,
@@ -2767,7 +2649,7 @@ mod tests {
assert!(can_cast_types(&input_type, &output_type));
let array = vec![Some(i128::MAX)];
- let array = create_decimal_array(array, 38, 3).unwrap();
+ let array = create_decimal128_array(array, 38, 3).unwrap();
let result = cast_with_options(
&array,
&output_type,
@@ -2786,7 +2668,7 @@ mod tests {
let output_type = DataType::Decimal256(20, 4);
assert!(can_cast_types(&input_type, &output_type));
let array = vec![Some(1123456), Some(2123456), Some(3123456), None];
- let array = create_decimal_array(array, 20, 3).unwrap();
+ let array = create_decimal128_array(array, 20, 3).unwrap();
generate_cast_test_case!(
&array,
Decimal256Array,
@@ -2888,69 +2770,69 @@ mod tests {
);
}
- #[test]
- fn test_cast_decimal_to_numeric() {
- let value_array: Vec<Option<i128>> = vec![Some(125), Some(225),
Some(325), None, Some(525)];
- let array = create_decimal_array(value_array, 38, 2).unwrap();
+ fn generate_decimal_to_numeric_cast_test_case<T>(array: &PrimitiveArray<T>)
+ where
+ T: ArrowPrimitiveType + DecimalType,
+ {
// u8
generate_cast_test_case!(
- &array,
+ array,
UInt8Array,
&DataType::UInt8,
vec![Some(1_u8), Some(2_u8), Some(3_u8), None, Some(5_u8)]
);
// u16
generate_cast_test_case!(
- &array,
+ array,
UInt16Array,
&DataType::UInt16,
vec![Some(1_u16), Some(2_u16), Some(3_u16), None, Some(5_u16)]
);
// u32
generate_cast_test_case!(
- &array,
+ array,
UInt32Array,
&DataType::UInt32,
vec![Some(1_u32), Some(2_u32), Some(3_u32), None, Some(5_u32)]
);
// u64
generate_cast_test_case!(
- &array,
+ array,
UInt64Array,
&DataType::UInt64,
vec![Some(1_u64), Some(2_u64), Some(3_u64), None, Some(5_u64)]
);
// i8
generate_cast_test_case!(
- &array,
+ array,
Int8Array,
&DataType::Int8,
vec![Some(1_i8), Some(2_i8), Some(3_i8), None, Some(5_i8)]
);
// i16
generate_cast_test_case!(
- &array,
+ array,
Int16Array,
&DataType::Int16,
vec![Some(1_i16), Some(2_i16), Some(3_i16), None, Some(5_i16)]
);
// i32
generate_cast_test_case!(
- &array,
+ array,
Int32Array,
&DataType::Int32,
vec![Some(1_i32), Some(2_i32), Some(3_i32), None, Some(5_i32)]
);
// i64
generate_cast_test_case!(
- &array,
+ array,
Int64Array,
&DataType::Int64,
vec![Some(1_i64), Some(2_i64), Some(3_i64), None, Some(5_i64)]
);
// f32
generate_cast_test_case!(
- &array,
+ array,
Float32Array,
&DataType::Float32,
vec![
@@ -2963,7 +2845,7 @@ mod tests {
);
// f64
generate_cast_test_case!(
- &array,
+ array,
Float64Array,
&DataType::Float64,
vec![
@@ -2974,10 +2856,18 @@ mod tests {
Some(5.25_f64)
]
);
+ }
+
+ #[test]
+ fn test_cast_decimal128_to_numeric() {
+ let value_array: Vec<Option<i128>> = vec![Some(125), Some(225),
Some(325), None, Some(525)];
+ let array = create_decimal128_array(value_array, 38, 2).unwrap();
+
+ generate_decimal_to_numeric_cast_test_case(&array);
// overflow test: out of range of max u8
let value_array: Vec<Option<i128>> = vec![Some(51300)];
- let array = create_decimal_array(value_array, 38, 2).unwrap();
+ let array = create_decimal128_array(value_array, 38, 2).unwrap();
let casted_array = cast_with_options(
&array,
&DataType::UInt8,
@@ -3004,7 +2894,7 @@ mod tests {
// overflow test: out of range of max i8
let value_array: Vec<Option<i128>> = vec![Some(24400)];
- let array = create_decimal_array(value_array, 38, 2).unwrap();
+ let array = create_decimal128_array(value_array, 38, 2).unwrap();
let casted_array = cast_with_options(
&array,
&DataType::Int8,
@@ -3041,7 +2931,7 @@ mod tests {
Some(112345678),
Some(112345679),
];
- let array = create_decimal_array(value_array, 38, 2).unwrap();
+ let array = create_decimal128_array(value_array, 38, 2).unwrap();
generate_cast_test_case!(
&array,
Float32Array,
@@ -3068,7 +2958,7 @@ mod tests {
Some(112345678901234568),
Some(112345678901234560),
];
- let array = create_decimal_array(value_array, 38, 2).unwrap();
+ let array = create_decimal128_array(value_array, 38, 2).unwrap();
generate_cast_test_case!(
&array,
Float64Array,
@@ -8381,7 +8271,7 @@ mod tests {
let output_type = DataType::Decimal128(20, -1);
assert!(can_cast_types(&input_type, &output_type));
let array = vec![Some(1123450), Some(2123455), Some(3123456), None];
- let input_decimal_array = create_decimal_array(array, 20, 0).unwrap();
+ let input_decimal_array = create_decimal128_array(array, 20,
0).unwrap();
let array = Arc::new(input_decimal_array) as ArrayRef;
generate_cast_test_case!(
&array,
@@ -8439,7 +8329,7 @@ mod tests {
let output_type = DataType::Decimal128(10, -2);
assert!(can_cast_types(&input_type, &output_type));
let array = vec![Some(123)];
- let input_decimal_array = create_decimal_array(array, 10, -1).unwrap();
+ let input_decimal_array = create_decimal128_array(array, 10,
-1).unwrap();
let array = Arc::new(input_decimal_array) as ArrayRef;
generate_cast_test_case!(&array, Decimal128Array, &output_type,
vec![Some(12_i128),]);
@@ -8449,7 +8339,7 @@ mod tests {
assert_eq!("1200", decimal_arr.value_as_string(0));
let array = vec![Some(125)];
- let input_decimal_array = create_decimal_array(array, 10, -1).unwrap();
+ let input_decimal_array = create_decimal128_array(array, 10,
-1).unwrap();
let array = Arc::new(input_decimal_array) as ArrayRef;
generate_cast_test_case!(&array, Decimal128Array, &output_type,
vec![Some(13_i128),]);
@@ -8465,7 +8355,7 @@ mod tests {
let output_type = DataType::Decimal256(10, 5);
assert!(can_cast_types(&input_type, &output_type));
let array = vec![Some(123456), Some(-123456)];
- let input_decimal_array = create_decimal_array(array, 10, 3).unwrap();
+ let input_decimal_array = create_decimal128_array(array, 10,
3).unwrap();
let array = Arc::new(input_decimal_array) as ArrayRef;
let hundred = i256::from_i128(100);
@@ -9287,15 +9177,15 @@ mod tests {
test_decimal_to_string::<Decimal128Type, i32>(
DataType::Utf8View,
- create_decimal_array(array128.clone(), 7, 3).unwrap(),
+ create_decimal128_array(array128.clone(), 7, 3).unwrap(),
);
test_decimal_to_string::<Decimal128Type, i32>(
DataType::Utf8,
- create_decimal_array(array128.clone(), 7, 3).unwrap(),
+ create_decimal128_array(array128.clone(), 7, 3).unwrap(),
);
test_decimal_to_string::<Decimal128Type, i64>(
DataType::LargeUtf8,
- create_decimal_array(array128, 7, 3).unwrap(),
+ create_decimal128_array(array128, 7, 3).unwrap(),
);
test_decimal_to_string::<Decimal256Type, i32>(
@@ -9969,7 +9859,7 @@ mod tests {
#[test]
fn test_decimal_to_decimal_throw_error_on_precision_overflow_same_scale() {
let array = vec![Some(123456789)];
- let array = create_decimal_array(array, 24, 2).unwrap();
+ let array = create_decimal128_array(array, 24, 2).unwrap();
let input_type = DataType::Decimal128(24, 2);
let output_type = DataType::Decimal128(6, 2);
assert!(can_cast_types(&input_type, &output_type));
@@ -9986,7 +9876,7 @@ mod tests {
#[test]
fn test_decimal_to_decimal_same_scale() {
let array = vec![Some(520)];
- let array = create_decimal_array(array, 4, 2).unwrap();
+ let array = create_decimal128_array(array, 4, 2).unwrap();
let input_type = DataType::Decimal128(4, 2);
let output_type = DataType::Decimal128(3, 2);
assert!(can_cast_types(&input_type, &output_type));
@@ -10004,18 +9894,18 @@ mod tests {
// Cast 0 of decimal(3, 0) type to decimal(2, 0)
assert_eq!(
&cast(
- &create_decimal_array(vec![Some(0)], 3, 0).unwrap(),
+ &create_decimal128_array(vec![Some(0)], 3, 0).unwrap(),
&DataType::Decimal128(2, 0)
)
.unwrap(),
- &(Arc::new(create_decimal_array(vec![Some(0)], 2, 0).unwrap()) as
ArrayRef)
+ &(Arc::new(create_decimal128_array(vec![Some(0)], 2, 0).unwrap())
as ArrayRef)
);
}
#[test]
fn test_decimal_to_decimal_throw_error_on_precision_overflow_lower_scale()
{
let array = vec![Some(123456789)];
- let array = create_decimal_array(array, 24, 4).unwrap();
+ let array = create_decimal128_array(array, 24, 4).unwrap();
let input_type = DataType::Decimal128(24, 4);
let output_type = DataType::Decimal128(6, 2);
assert!(can_cast_types(&input_type, &output_type));
@@ -10032,7 +9922,7 @@ mod tests {
#[test]
fn
test_decimal_to_decimal_throw_error_on_precision_overflow_greater_scale() {
let array = vec![Some(123456789)];
- let array = create_decimal_array(array, 24, 2).unwrap();
+ let array = create_decimal128_array(array, 24, 2).unwrap();
let input_type = DataType::Decimal128(24, 2);
let output_type = DataType::Decimal128(6, 3);
assert!(can_cast_types(&input_type, &output_type));
@@ -10049,7 +9939,7 @@ mod tests {
#[test]
fn test_decimal_to_decimal_throw_error_on_precision_overflow_diff_type() {
let array = vec![Some(123456789)];
- let array = create_decimal_array(array, 24, 2).unwrap();
+ let array = create_decimal128_array(array, 24, 2).unwrap();
let input_type = DataType::Decimal128(24, 2);
let output_type = DataType::Decimal256(6, 2);
assert!(can_cast_types(&input_type, &output_type));
diff --git a/arrow-data/src/data.rs b/arrow-data/src/data.rs
index 4314b550d6..dce1a853c2 100644
--- a/arrow-data/src/data.rs
+++ b/arrow-data/src/data.rs
@@ -84,6 +84,8 @@ pub(crate) fn new_buffers(data_type: &DataType, capacity:
usize) -> [MutableBuff
| DataType::Float16
| DataType::Float32
| DataType::Float64
+ | DataType::Decimal128(_, _)
+ | DataType::Decimal256(_, _)
| DataType::Date32
| DataType::Time32(_)
| DataType::Date64
@@ -140,10 +142,6 @@ pub(crate) fn new_buffers(data_type: &DataType, capacity:
usize) -> [MutableBuff
DataType::FixedSizeList(_, _) | DataType::Struct(_) |
DataType::RunEndEncoded(_, _) => {
[empty_buffer, MutableBuffer::new(0)]
}
- DataType::Decimal128(_, _) | DataType::Decimal256(_, _) => [
- MutableBuffer::new(capacity * mem::size_of::<u8>()),
- empty_buffer,
- ],
DataType::Union(_, mode) => {
let type_ids = MutableBuffer::new(capacity * mem::size_of::<i8>());
match mode {
diff --git a/arrow-integration-test/src/datatype.rs
b/arrow-integration-test/src/datatype.rs
index e45e94c24e..24e02c8430 100644
--- a/arrow-integration-test/src/datatype.rs
+++ b/arrow-integration-test/src/datatype.rs
@@ -60,14 +60,12 @@ pub fn data_type_from_json(json: &serde_json::Value) ->
Result<DataType> {
_ => 128, // Default bit width
};
- if bit_width == 128 {
- Ok(DataType::Decimal128(precision, scale))
- } else if bit_width == 256 {
- Ok(DataType::Decimal256(precision, scale))
- } else {
- Err(ArrowError::ParseError(
+ match bit_width {
+ 128 => Ok(DataType::Decimal128(precision, scale)),
+ 256 => Ok(DataType::Decimal256(precision, scale)),
+ _ => Err(ArrowError::ParseError(
"Decimal bit_width invalid".to_string(),
- ))
+ )),
}
}
Some(s) if s == "floatingpoint" => match map.get("precision") {
diff --git a/arrow-ipc/src/convert.rs b/arrow-ipc/src/convert.rs
index 37c5a19439..aadeb77033 100644
--- a/arrow-ipc/src/convert.rs
+++ b/arrow-ipc/src/convert.rs
@@ -454,18 +454,12 @@ pub(crate) fn get_data_type(field: crate::Field,
may_be_dictionary: bool) -> Dat
crate::Type::Decimal => {
let fsb = field.type_as_decimal().unwrap();
let bit_width = fsb.bitWidth();
- if bit_width == 128 {
- DataType::Decimal128(
- fsb.precision().try_into().unwrap(),
- fsb.scale().try_into().unwrap(),
- )
- } else if bit_width == 256 {
- DataType::Decimal256(
- fsb.precision().try_into().unwrap(),
- fsb.scale().try_into().unwrap(),
- )
- } else {
- panic!("Unexpected decimal bit width {bit_width}")
+ let precision: u8 = fsb.precision().try_into().unwrap();
+ let scale: i8 = fsb.scale().try_into().unwrap();
+ match bit_width {
+ 128 => DataType::Decimal128(precision, scale),
+ 256 => DataType::Decimal256(precision, scale),
+ _ => panic!("Unexpected decimal bit width {bit_width}"),
}
}
crate::Type::Union => {
diff --git a/arrow-ord/src/sort.rs b/arrow-ord/src/sort.rs
index 92ee93e1b6..7894999157 100644
--- a/arrow-ord/src/sort.rs
+++ b/arrow-ord/src/sort.rs
@@ -795,10 +795,15 @@ mod tests {
use rand::seq::SliceRandom;
use rand::{Rng, RngCore, SeedableRng};
- fn create_decimal128_array(data: Vec<Option<i128>>) -> Decimal128Array {
+ fn create_decimal_array<T: DecimalType>(
+ data: Vec<Option<usize>>,
+ precision: u8,
+ scale: i8,
+ ) -> PrimitiveArray<T> {
data.into_iter()
- .collect::<Decimal128Array>()
- .with_precision_and_scale(23, 6)
+ .map(|x| x.and_then(T::Native::from_usize))
+ .collect::<PrimitiveArray<T>>()
+ .with_precision_and_scale(precision, scale)
.unwrap()
}
@@ -809,13 +814,15 @@ mod tests {
.unwrap()
}
- fn test_sort_to_indices_decimal128_array(
- data: Vec<Option<i128>>,
+ fn test_sort_to_indices_decimal_array<T: DecimalType>(
+ data: Vec<Option<usize>>,
options: Option<SortOptions>,
limit: Option<usize>,
expected_data: Vec<u32>,
+ precision: u8,
+ scale: i8,
) {
- let output = create_decimal128_array(data);
+ let output = create_decimal_array::<T>(data, precision, scale);
let expected = UInt32Array::from(expected_data);
let output = sort_to_indices(&(Arc::new(output) as ArrayRef), options,
limit).unwrap();
assert_eq!(output, expected)
@@ -833,14 +840,16 @@ mod tests {
assert_eq!(output, expected)
}
- fn test_sort_decimal128_array(
- data: Vec<Option<i128>>,
+ fn test_sort_decimal_array<T: DecimalType>(
+ data: Vec<Option<usize>>,
options: Option<SortOptions>,
limit: Option<usize>,
- expected_data: Vec<Option<i128>>,
+ expected_data: Vec<Option<usize>>,
+ p: u8,
+ s: i8,
) {
- let output = create_decimal128_array(data);
- let expected = Arc::new(create_decimal128_array(expected_data)) as
ArrayRef;
+ let output = create_decimal_array::<T>(data, p, s);
+ let expected = Arc::new(create_decimal_array::<T>(expected_data, p,
s)) as ArrayRef;
let output = match limit {
Some(_) => sort_limit(&(Arc::new(output) as ArrayRef), options,
limit).unwrap(),
_ => sort(&(Arc::new(output) as ArrayRef), options).unwrap(),
@@ -1921,17 +1930,18 @@ mod tests {
);
}
- #[test]
- fn test_sort_indices_decimal128() {
+ fn test_sort_indices_decimal<T: DecimalType>(precision: u8, scale: i8) {
// decimal default
- test_sort_to_indices_decimal128_array(
+ test_sort_to_indices_decimal_array::<T>(
vec![None, Some(5), Some(2), Some(3), Some(1), Some(4), None],
None,
None,
vec![0, 6, 4, 2, 3, 5, 1],
+ precision,
+ scale,
);
// decimal descending
- test_sort_to_indices_decimal128_array(
+ test_sort_to_indices_decimal_array::<T>(
vec![None, Some(5), Some(2), Some(3), Some(1), Some(4), None],
Some(SortOptions {
descending: true,
@@ -1939,9 +1949,11 @@ mod tests {
}),
None,
vec![1, 5, 3, 2, 4, 0, 6],
+ precision,
+ scale,
);
// decimal null_first and descending
- test_sort_to_indices_decimal128_array(
+ test_sort_to_indices_decimal_array::<T>(
vec![None, Some(5), Some(2), Some(3), Some(1), Some(4), None],
Some(SortOptions {
descending: true,
@@ -1949,9 +1961,11 @@ mod tests {
}),
None,
vec![0, 6, 1, 5, 3, 2, 4],
+ precision,
+ scale,
);
// decimal null_first
- test_sort_to_indices_decimal128_array(
+ test_sort_to_indices_decimal_array::<T>(
vec![None, Some(5), Some(2), Some(3), Some(1), Some(4), None],
Some(SortOptions {
descending: false,
@@ -1959,16 +1973,20 @@ mod tests {
}),
None,
vec![0, 6, 4, 2, 3, 5, 1],
+ precision,
+ scale,
);
// limit
- test_sort_to_indices_decimal128_array(
+ test_sort_to_indices_decimal_array::<T>(
vec![None, Some(5), Some(2), Some(3), Some(1), Some(4), None],
None,
Some(3),
vec![0, 6, 4],
+ precision,
+ scale,
);
// limit descending
- test_sort_to_indices_decimal128_array(
+ test_sort_to_indices_decimal_array::<T>(
vec![None, Some(5), Some(2), Some(3), Some(1), Some(4), None],
Some(SortOptions {
descending: true,
@@ -1976,9 +1994,11 @@ mod tests {
}),
Some(3),
vec![1, 5, 3],
+ precision,
+ scale,
);
// limit descending null_first
- test_sort_to_indices_decimal128_array(
+ test_sort_to_indices_decimal_array::<T>(
vec![None, Some(5), Some(2), Some(3), Some(1), Some(4), None],
Some(SortOptions {
descending: true,
@@ -1986,9 +2006,11 @@ mod tests {
}),
Some(3),
vec![0, 6, 1],
+ precision,
+ scale,
);
// limit null_first
- test_sort_to_indices_decimal128_array(
+ test_sort_to_indices_decimal_array::<T>(
vec![None, Some(5), Some(2), Some(3), Some(1), Some(4), None],
Some(SortOptions {
descending: false,
@@ -1996,85 +2018,19 @@ mod tests {
}),
Some(3),
vec![0, 6, 4],
+ precision,
+ scale,
);
}
#[test]
- fn test_sort_indices_decimal256() {
- let data = vec![
- None,
- Some(i256::from_i128(5)),
- Some(i256::from_i128(2)),
- Some(i256::from_i128(3)),
- Some(i256::from_i128(1)),
- Some(i256::from_i128(4)),
- None,
- ];
+ fn test_sort_indices_decimal128() {
+ test_sort_indices_decimal::<Decimal128Type>(23, 6);
+ }
- // decimal default
- test_sort_to_indices_decimal256_array(data.clone(), None, None,
vec![0, 6, 4, 2, 3, 5, 1]);
- // decimal descending
- test_sort_to_indices_decimal256_array(
- data.clone(),
- Some(SortOptions {
- descending: true,
- nulls_first: false,
- }),
- None,
- vec![1, 5, 3, 2, 4, 0, 6],
- );
- // decimal null_first and descending
- test_sort_to_indices_decimal256_array(
- data.clone(),
- Some(SortOptions {
- descending: true,
- nulls_first: true,
- }),
- None,
- vec![0, 6, 1, 5, 3, 2, 4],
- );
- // decimal null_first
- test_sort_to_indices_decimal256_array(
- data.clone(),
- Some(SortOptions {
- descending: false,
- nulls_first: true,
- }),
- None,
- vec![0, 6, 4, 2, 3, 5, 1],
- );
- // limit
- test_sort_to_indices_decimal256_array(data.clone(), None, Some(3),
vec![0, 6, 4]);
- // limit descending
- test_sort_to_indices_decimal256_array(
- data.clone(),
- Some(SortOptions {
- descending: true,
- nulls_first: false,
- }),
- Some(3),
- vec![1, 5, 3],
- );
- // limit descending null_first
- test_sort_to_indices_decimal256_array(
- data.clone(),
- Some(SortOptions {
- descending: true,
- nulls_first: true,
- }),
- Some(3),
- vec![0, 6, 1],
- );
- // limit null_first
- test_sort_to_indices_decimal256_array(
- data,
- Some(SortOptions {
- descending: false,
- nulls_first: true,
- }),
- Some(3),
- vec![0, 6, 4],
- );
+ #[test]
+ fn test_sort_indices_decimal256() {
+ test_sort_indices_decimal::<Decimal256Type>(53, 6);
}
#[test]
@@ -2127,17 +2083,18 @@ mod tests {
);
}
- #[test]
- fn test_sort_decimal128() {
+ fn test_sort_decimal<T: DecimalType>(precision: u8, scale: i8) {
// decimal default
- test_sort_decimal128_array(
+ test_sort_decimal_array::<T>(
vec![None, Some(5), Some(2), Some(3), Some(1), Some(4), None],
None,
None,
vec![None, None, Some(1), Some(2), Some(3), Some(4), Some(5)],
+ precision,
+ scale,
);
// decimal descending
- test_sort_decimal128_array(
+ test_sort_decimal_array::<T>(
vec![None, Some(5), Some(2), Some(3), Some(1), Some(4), None],
Some(SortOptions {
descending: true,
@@ -2145,9 +2102,11 @@ mod tests {
}),
None,
vec![Some(5), Some(4), Some(3), Some(2), Some(1), None, None],
+ precision,
+ scale,
);
// decimal null_first and descending
- test_sort_decimal128_array(
+ test_sort_decimal_array::<T>(
vec![None, Some(5), Some(2), Some(3), Some(1), Some(4), None],
Some(SortOptions {
descending: true,
@@ -2155,9 +2114,11 @@ mod tests {
}),
None,
vec![None, None, Some(5), Some(4), Some(3), Some(2), Some(1)],
+ precision,
+ scale,
);
// decimal null_first
- test_sort_decimal128_array(
+ test_sort_decimal_array::<T>(
vec![None, Some(5), Some(2), Some(3), Some(1), Some(4), None],
Some(SortOptions {
descending: false,
@@ -2165,16 +2126,20 @@ mod tests {
}),
None,
vec![None, None, Some(1), Some(2), Some(3), Some(4), Some(5)],
+ precision,
+ scale,
);
// limit
- test_sort_decimal128_array(
+ test_sort_decimal_array::<T>(
vec![None, Some(5), Some(2), Some(3), Some(1), Some(4), None],
None,
Some(3),
vec![None, None, Some(1)],
+ precision,
+ scale,
);
// limit descending
- test_sort_decimal128_array(
+ test_sort_decimal_array::<T>(
vec![None, Some(5), Some(2), Some(3), Some(1), Some(4), None],
Some(SortOptions {
descending: true,
@@ -2182,9 +2147,11 @@ mod tests {
}),
Some(3),
vec![Some(5), Some(4), Some(3)],
+ precision,
+ scale,
);
// limit descending null_first
- test_sort_decimal128_array(
+ test_sort_decimal_array::<T>(
vec![None, Some(5), Some(2), Some(3), Some(1), Some(4), None],
Some(SortOptions {
descending: true,
@@ -2192,9 +2159,11 @@ mod tests {
}),
Some(3),
vec![None, None, Some(5)],
+ precision,
+ scale,
);
// limit null_first
- test_sort_decimal128_array(
+ test_sort_decimal_array::<T>(
vec![None, Some(5), Some(2), Some(3), Some(1), Some(4), None],
Some(SortOptions {
descending: false,
@@ -2202,118 +2171,19 @@ mod tests {
}),
Some(3),
vec![None, None, Some(1)],
+ precision,
+ scale,
);
}
+ #[test]
+ fn test_sort_decimal128() {
+ test_sort_decimal::<Decimal128Type>(23, 6);
+ }
+
#[test]
fn test_sort_decimal256() {
- let data = vec![
- None,
- Some(i256::from_i128(5)),
- Some(i256::from_i128(2)),
- Some(i256::from_i128(3)),
- Some(i256::from_i128(1)),
- Some(i256::from_i128(4)),
- None,
- ];
- // decimal default
- test_sort_decimal256_array(
- data.clone(),
- None,
- None,
- [None, None, Some(1), Some(2), Some(3), Some(4), Some(5)]
- .iter()
- .map(|v| v.map(i256::from_i128))
- .collect(),
- );
- // decimal descending
- test_sort_decimal256_array(
- data.clone(),
- Some(SortOptions {
- descending: true,
- nulls_first: false,
- }),
- None,
- [Some(5), Some(4), Some(3), Some(2), Some(1), None, None]
- .iter()
- .map(|v| v.map(i256::from_i128))
- .collect(),
- );
- // decimal null_first and descending
- test_sort_decimal256_array(
- data.clone(),
- Some(SortOptions {
- descending: true,
- nulls_first: true,
- }),
- None,
- [None, None, Some(5), Some(4), Some(3), Some(2), Some(1)]
- .iter()
- .map(|v| v.map(i256::from_i128))
- .collect(),
- );
- // decimal null_first
- test_sort_decimal256_array(
- data.clone(),
- Some(SortOptions {
- descending: false,
- nulls_first: true,
- }),
- None,
- [None, None, Some(1), Some(2), Some(3), Some(4), Some(5)]
- .iter()
- .map(|v| v.map(i256::from_i128))
- .collect(),
- );
- // limit
- test_sort_decimal256_array(
- data.clone(),
- None,
- Some(3),
- [None, None, Some(1)]
- .iter()
- .map(|v| v.map(i256::from_i128))
- .collect(),
- );
- // limit descending
- test_sort_decimal256_array(
- data.clone(),
- Some(SortOptions {
- descending: true,
- nulls_first: false,
- }),
- Some(3),
- [Some(5), Some(4), Some(3)]
- .iter()
- .map(|v| v.map(i256::from_i128))
- .collect(),
- );
- // limit descending null_first
- test_sort_decimal256_array(
- data.clone(),
- Some(SortOptions {
- descending: true,
- nulls_first: true,
- }),
- Some(3),
- [None, None, Some(5)]
- .iter()
- .map(|v| v.map(i256::from_i128))
- .collect(),
- );
- // limit null_first
- test_sort_decimal256_array(
- data,
- Some(SortOptions {
- descending: false,
- nulls_first: true,
- }),
- Some(3),
- [None, None, Some(1)]
- .iter()
- .map(|v| v.map(i256::from_i128))
- .collect(),
- );
+ test_sort_decimal::<Decimal256Type>(53, 6);
}
#[test]
diff --git a/arrow-schema/src/ffi.rs b/arrow-schema/src/ffi.rs
index 96c8097498..d86fb66190 100644
--- a/arrow-schema/src/ffi.rs
+++ b/arrow-schema/src/ffi.rs
@@ -510,9 +510,6 @@ impl TryFrom<&FFI_ArrowSchema> for DataType {
DataType::Decimal128(parsed_precision,
parsed_scale)
},
[precision, scale, bits] => {
- if *bits != "128" && *bits != "256" {
- return
Err(ArrowError::CDataInterface("Only 128/256 bit wide decimal is supported in
the Rust implementation".to_string()));
- }
let parsed_precision =
precision.parse::<u8>().map_err(|_| {
ArrowError::CDataInterface(
"The decimal type requires an integer
precision".to_string(),
@@ -523,10 +520,10 @@ impl TryFrom<&FFI_ArrowSchema> for DataType {
"The decimal type requires an integer
scale".to_string(),
)
})?;
- if *bits == "128" {
- DataType::Decimal128(parsed_precision,
parsed_scale)
- } else {
- DataType::Decimal256(parsed_precision,
parsed_scale)
+ match *bits {
+ "128" =>
DataType::Decimal128(parsed_precision, parsed_scale),
+ "256" =>
DataType::Decimal256(parsed_precision, parsed_scale),
+ _ => return
Err(ArrowError::CDataInterface("Only 128- and 256- bit wide decimals are
supported in the Rust implementation".to_string())),
}
}
_ => {
diff --git a/arrow/benches/builder.rs b/arrow/benches/builder.rs
index 2776924d8e..4f5f38eadf 100644
--- a/arrow/benches/builder.rs
+++ b/arrow/benches/builder.rs
@@ -126,7 +126,7 @@ fn bench_decimal128(c: &mut Criterion) {
}
fn bench_decimal256(c: &mut Criterion) {
- c.bench_function("bench_decimal128_builder", |b| {
+ c.bench_function("bench_decimal256_builder", |b| {
b.iter(|| {
let mut rng = rand::rng();
let mut decimal_builder =
Decimal256Builder::with_capacity(BATCH_SIZE);
diff --git a/arrow/tests/array_cast.rs b/arrow/tests/array_cast.rs
index ef5ca60417..da7d37fc48 100644
--- a/arrow/tests/array_cast.rs
+++ b/arrow/tests/array_cast.rs
@@ -261,7 +261,7 @@ fn get_arrays_of_all_types() -> Vec<ArrayRef> {
Arc::new(DurationMillisecondArray::from(vec![1000, 2000])),
Arc::new(DurationMicrosecondArray::from(vec![1000, 2000])),
Arc::new(DurationNanosecondArray::from(vec![1000, 2000])),
- Arc::new(create_decimal_array(vec![Some(1), Some(2), Some(3)], 38,
0).unwrap()),
+ Arc::new(create_decimal128_array(vec![Some(1), Some(2), Some(3)], 38,
0).unwrap()),
make_dictionary_primitive::<Int8Type, Decimal128Type>(vec![1, 2]),
make_dictionary_primitive::<Int16Type, Decimal128Type>(vec![1, 2]),
make_dictionary_primitive::<Int32Type, Decimal128Type>(vec![1, 2]),
@@ -411,7 +411,7 @@ fn make_dictionary_utf8<K: ArrowDictionaryKeyType>() ->
ArrayRef {
Arc::new(b.finish())
}
-fn create_decimal_array(
+fn create_decimal128_array(
array: Vec<Option<i128>>,
precision: u8,
scale: i8,