1use crate::cast::*;
19
20pub trait DecimalCast: Sized {
23 fn to_i32(self) -> Option<i32>;
25
26 fn to_i64(self) -> Option<i64>;
28
29 fn to_i128(self) -> Option<i128>;
31
32 fn to_i256(self) -> Option<i256>;
34
35 fn from_decimal<T: DecimalCast>(n: T) -> Option<Self>;
37
38 fn from_f64(n: f64) -> Option<Self>;
40}
41
42impl DecimalCast for i32 {
43 fn to_i32(self) -> Option<i32> {
44 Some(self)
45 }
46
47 fn to_i64(self) -> Option<i64> {
48 Some(self as i64)
49 }
50
51 fn to_i128(self) -> Option<i128> {
52 Some(self as i128)
53 }
54
55 fn to_i256(self) -> Option<i256> {
56 Some(i256::from_i128(self as i128))
57 }
58
59 fn from_decimal<T: DecimalCast>(n: T) -> Option<Self> {
60 n.to_i32()
61 }
62
63 fn from_f64(n: f64) -> Option<Self> {
64 n.to_i32()
65 }
66}
67
68impl DecimalCast for i64 {
69 fn to_i32(self) -> Option<i32> {
70 i32::try_from(self).ok()
71 }
72
73 fn to_i64(self) -> Option<i64> {
74 Some(self)
75 }
76
77 fn to_i128(self) -> Option<i128> {
78 Some(self as i128)
79 }
80
81 fn to_i256(self) -> Option<i256> {
82 Some(i256::from_i128(self as i128))
83 }
84
85 fn from_decimal<T: DecimalCast>(n: T) -> Option<Self> {
86 n.to_i64()
87 }
88
89 fn from_f64(n: f64) -> Option<Self> {
90 num_traits::ToPrimitive::to_i64(&n)
93 }
94}
95
96impl DecimalCast for i128 {
97 fn to_i32(self) -> Option<i32> {
98 i32::try_from(self).ok()
99 }
100
101 fn to_i64(self) -> Option<i64> {
102 i64::try_from(self).ok()
103 }
104
105 fn to_i128(self) -> Option<i128> {
106 Some(self)
107 }
108
109 fn to_i256(self) -> Option<i256> {
110 Some(i256::from_i128(self))
111 }
112
113 fn from_decimal<T: DecimalCast>(n: T) -> Option<Self> {
114 n.to_i128()
115 }
116
117 fn from_f64(n: f64) -> Option<Self> {
118 n.to_i128()
119 }
120}
121
122impl DecimalCast for i256 {
123 fn to_i32(self) -> Option<i32> {
124 self.to_i128().map(|x| i32::try_from(x).ok())?
125 }
126
127 fn to_i64(self) -> Option<i64> {
128 self.to_i128().map(|x| i64::try_from(x).ok())?
129 }
130
131 fn to_i128(self) -> Option<i128> {
132 self.to_i128()
133 }
134
135 fn to_i256(self) -> Option<i256> {
136 Some(self)
137 }
138
139 fn from_decimal<T: DecimalCast>(n: T) -> Option<Self> {
140 n.to_i256()
141 }
142
143 fn from_f64(n: f64) -> Option<Self> {
144 i256::from_f64(n)
145 }
146}
147
148#[expect(clippy::type_complexity)]
161fn make_upscaler<I: DecimalType, O: DecimalType>(
162 input_precision: u8,
163 input_scale: i8,
164 output_precision: u8,
165 output_scale: i8,
166) -> Option<(
167 impl Fn(I::Native) -> Option<O::Native>,
168 Option<impl Fn(I::Native) -> O::Native>,
169)>
170where
171 I::Native: DecimalCast + ArrowNativeTypeOp,
172 O::Native: DecimalCast + ArrowNativeTypeOp,
173{
174 let delta_scale = output_scale - input_scale;
175
176 let max = O::MAX_FOR_EACH_PRECISION.get(delta_scale as usize)?;
181 let mul = max.add_wrapping(O::Native::ONE);
182 let f_fallible = move |x| O::Native::from_decimal(x).and_then(|x| x.mul_checked(mul).ok());
183
184 let is_infallible_cast = (input_precision as i8) + delta_scale <= (output_precision as i8);
191 let f_infallible = is_infallible_cast
192 .then_some(move |x| O::Native::from_decimal(x).unwrap().mul_wrapping(mul));
193 Some((f_fallible, f_infallible))
194}
195
196#[expect(clippy::type_complexity)]
210fn make_downscaler<I: DecimalType, O: DecimalType>(
211 input_precision: u8,
212 input_scale: i8,
213 output_precision: u8,
214 output_scale: i8,
215) -> Option<(
216 impl Fn(I::Native) -> Option<O::Native>,
217 Option<impl Fn(I::Native) -> O::Native>,
218)>
219where
220 I::Native: DecimalCast + ArrowNativeTypeOp,
221 O::Native: DecimalCast + ArrowNativeTypeOp,
222{
223 let delta_scale = input_scale - output_scale;
224
225 let max = I::MAX_FOR_EACH_PRECISION.get(delta_scale as usize)?;
232
233 let div = max.add_wrapping(I::Native::ONE);
234 let half = div.div_wrapping(I::Native::ONE.add_wrapping(I::Native::ONE));
235 let half_neg = half.neg_wrapping();
236
237 let f_fallible = move |x: I::Native| {
238 let d = x.div_wrapping(div);
240 let r = x.mod_wrapping(div);
241
242 let adjusted = match x >= I::Native::ZERO {
244 true if r >= half => d.add_wrapping(I::Native::ONE),
245 false if r <= half_neg => d.sub_wrapping(I::Native::ONE),
246 _ => d,
247 };
248 O::Native::from_decimal(adjusted)
249 };
250
251 let is_infallible_cast = (input_precision as i8) - delta_scale < (output_precision as i8);
262 let f_infallible = is_infallible_cast.then_some(move |x| f_fallible(x).unwrap());
263 Some((f_fallible, f_infallible))
264}
265
266fn apply_rescaler<I: DecimalType, O: DecimalType>(
270 value: I::Native,
271 output_precision: u8,
272 f: impl Fn(I::Native) -> Option<O::Native>,
273 f_infallible: Option<impl Fn(I::Native) -> O::Native>,
274) -> Option<O::Native>
275where
276 I::Native: DecimalCast,
277 O::Native: DecimalCast,
278{
279 if let Some(f_infallible) = f_infallible {
280 Some(f_infallible(value))
281 } else {
282 f(value).filter(|v| O::is_valid_decimal_precision(*v, output_precision))
283 }
284}
285
286pub fn rescale_decimal<I: DecimalType, O: DecimalType>(
302 value: I::Native,
303 input_precision: u8,
304 input_scale: i8,
305 output_precision: u8,
306 output_scale: i8,
307) -> Option<O::Native>
308where
309 I::Native: DecimalCast + ArrowNativeTypeOp,
310 O::Native: DecimalCast + ArrowNativeTypeOp,
311{
312 validate_decimal_precision_and_scale::<I>(input_precision, input_scale).ok()?;
313 validate_decimal_precision_and_scale::<O>(output_precision, output_scale).ok()?;
314
315 if input_scale <= output_scale {
316 let (f, f_infallible) =
317 make_upscaler::<I, O>(input_precision, input_scale, output_precision, output_scale)?;
318 apply_rescaler::<I, O>(value, output_precision, f, f_infallible)
319 } else {
320 let Some((f, f_infallible)) =
321 make_downscaler::<I, O>(input_precision, input_scale, output_precision, output_scale)
322 else {
323 return Some(O::Native::ZERO);
325 };
326 apply_rescaler::<I, O>(value, output_precision, f, f_infallible)
327 }
328}
329
330fn cast_decimal_to_decimal_error<I, O>(
331 output_precision: u8,
332 output_scale: i8,
333) -> impl Fn(<I as ArrowPrimitiveType>::Native) -> ArrowError
334where
335 I: DecimalType,
336 O: DecimalType,
337 I::Native: DecimalCast + ArrowNativeTypeOp,
338 O::Native: DecimalCast + ArrowNativeTypeOp,
339{
340 move |x: I::Native| {
341 ArrowError::CastError(format!(
342 "Cannot cast to {}({}, {}). Overflowing on {:?}",
343 O::PREFIX,
344 output_precision,
345 output_scale,
346 x
347 ))
348 }
349}
350
351fn apply_decimal_cast<I: DecimalType, O: DecimalType>(
352 array: &PrimitiveArray<I>,
353 output_precision: u8,
354 output_scale: i8,
355 f_fallible: impl Fn(I::Native) -> Option<O::Native>,
356 f_infallible: Option<impl Fn(I::Native) -> O::Native>,
357 cast_options: &CastOptions,
358) -> Result<PrimitiveArray<O>, ArrowError>
359where
360 I::Native: DecimalCast + ArrowNativeTypeOp,
361 O::Native: DecimalCast + ArrowNativeTypeOp,
362{
363 let array = if let Some(f_infallible) = f_infallible {
364 array.unary(f_infallible)
365 } else if cast_options.safe {
366 array.unary_opt(|x| {
367 f_fallible(x).filter(|v| O::is_valid_decimal_precision(*v, output_precision))
368 })
369 } else {
370 let error = cast_decimal_to_decimal_error::<I, O>(output_precision, output_scale);
371 array.try_unary(|x| {
372 f_fallible(x).ok_or_else(|| error(x)).and_then(|v| {
373 O::validate_decimal_precision(v, output_precision, output_scale).map(|()| v)
374 })
375 })?
376 };
377 Ok(array)
378}
379
380fn convert_to_smaller_scale_decimal<I, O>(
381 array: &PrimitiveArray<I>,
382 input_precision: u8,
383 input_scale: i8,
384 output_precision: u8,
385 output_scale: i8,
386 cast_options: &CastOptions,
387) -> Result<PrimitiveArray<O>, ArrowError>
388where
389 I: DecimalType,
390 O: DecimalType,
391 I::Native: DecimalCast + ArrowNativeTypeOp,
392 O::Native: DecimalCast + ArrowNativeTypeOp,
393{
394 if let Some((f_fallible, f_infallible)) =
395 make_downscaler::<I, O>(input_precision, input_scale, output_precision, output_scale)
396 {
397 apply_decimal_cast(
398 array,
399 output_precision,
400 output_scale,
401 f_fallible,
402 f_infallible,
403 cast_options,
404 )
405 } else {
406 let zeros = vec![O::Native::ZERO; array.len()];
408 Ok(PrimitiveArray::new(zeros.into(), array.nulls().cloned()))
409 }
410}
411
412fn convert_to_bigger_or_equal_scale_decimal<I, O>(
413 array: &PrimitiveArray<I>,
414 input_precision: u8,
415 input_scale: i8,
416 output_precision: u8,
417 output_scale: i8,
418 cast_options: &CastOptions,
419) -> Result<PrimitiveArray<O>, ArrowError>
420where
421 I: DecimalType,
422 O: DecimalType,
423 I::Native: DecimalCast + ArrowNativeTypeOp,
424 O::Native: DecimalCast + ArrowNativeTypeOp,
425{
426 if let Some((f, f_infallible)) =
427 make_upscaler::<I, O>(input_precision, input_scale, output_precision, output_scale)
428 {
429 apply_decimal_cast(
430 array,
431 output_precision,
432 output_scale,
433 f,
434 f_infallible,
435 cast_options,
436 )
437 } else {
438 Err(ArrowError::CastError(format!(
440 "Cannot cast to {}({}, {}). Value overflows for output scale",
441 O::PREFIX,
442 output_precision,
443 output_scale
444 )))
445 }
446}
447
448pub(crate) fn cast_decimal_to_decimal_same_type<T>(
450 array: &PrimitiveArray<T>,
451 input_precision: u8,
452 input_scale: i8,
453 output_precision: u8,
454 output_scale: i8,
455 cast_options: &CastOptions,
456) -> Result<ArrayRef, ArrowError>
457where
458 T: DecimalType,
459 T::Native: DecimalCast + ArrowNativeTypeOp,
460{
461 let array: PrimitiveArray<T> =
462 if input_scale == output_scale && input_precision <= output_precision {
463 array.clone()
464 } else if input_scale <= output_scale {
465 convert_to_bigger_or_equal_scale_decimal::<T, T>(
466 array,
467 input_precision,
468 input_scale,
469 output_precision,
470 output_scale,
471 cast_options,
472 )?
473 } else {
474 convert_to_smaller_scale_decimal::<T, T>(
476 array,
477 input_precision,
478 input_scale,
479 output_precision,
480 output_scale,
481 cast_options,
482 )?
483 };
484
485 Ok(Arc::new(array.with_precision_and_scale(
486 output_precision,
487 output_scale,
488 )?))
489}
490
491pub(crate) fn cast_decimal_to_decimal<I, O>(
493 array: &PrimitiveArray<I>,
494 input_precision: u8,
495 input_scale: i8,
496 output_precision: u8,
497 output_scale: i8,
498 cast_options: &CastOptions,
499) -> Result<ArrayRef, ArrowError>
500where
501 I: DecimalType,
502 O: DecimalType,
503 I::Native: DecimalCast + ArrowNativeTypeOp,
504 O::Native: DecimalCast + ArrowNativeTypeOp,
505{
506 let array: PrimitiveArray<O> = if input_scale > output_scale {
507 convert_to_smaller_scale_decimal::<I, O>(
508 array,
509 input_precision,
510 input_scale,
511 output_precision,
512 output_scale,
513 cast_options,
514 )?
515 } else {
516 convert_to_bigger_or_equal_scale_decimal::<I, O>(
517 array,
518 input_precision,
519 input_scale,
520 output_precision,
521 output_scale,
522 cast_options,
523 )?
524 };
525
526 Ok(Arc::new(array.with_precision_and_scale(
527 output_precision,
528 output_scale,
529 )?))
530}
531
532pub fn parse_string_to_decimal_native<T: DecimalType>(
535 value_str: &str,
536 scale: usize,
537) -> Result<T::Native, ArrowError>
538where
539 T::Native: DecimalCast + ArrowNativeTypeOp,
540{
541 let value_str = value_str.trim();
542 let parts: Vec<&str> = value_str.split('.').collect();
543 if parts.len() > 2 {
544 return Err(ArrowError::InvalidArgumentError(format!(
545 "Invalid decimal format: {value_str:?}"
546 )));
547 }
548
549 let (negative, first_part) = if parts[0].is_empty() {
550 (false, parts[0])
551 } else {
552 match parts[0].as_bytes()[0] {
553 b'-' => (true, &parts[0][1..]),
554 b'+' => (false, &parts[0][1..]),
555 _ => (false, parts[0]),
556 }
557 };
558
559 let integers = first_part;
560 let decimals = if parts.len() == 2 { parts[1] } else { "" };
561
562 if integers.is_empty() && decimals.is_empty() {
563 return Err(ArrowError::InvalidArgumentError(format!(
564 "Invalid decimal format: {value_str:?}"
565 )));
566 }
567
568 if !integers.is_empty() && !integers.as_bytes()[0].is_ascii_digit() {
569 return Err(ArrowError::InvalidArgumentError(format!(
570 "Invalid decimal format: {value_str:?}"
571 )));
572 }
573
574 if !decimals.is_empty() && !decimals.as_bytes()[0].is_ascii_digit() {
575 return Err(ArrowError::InvalidArgumentError(format!(
576 "Invalid decimal format: {value_str:?}"
577 )));
578 }
579
580 let mut number_decimals = if decimals.len() > scale {
582 let decimal_number = i256::from_string(decimals).ok_or_else(|| {
583 ArrowError::InvalidArgumentError(format!("Cannot parse decimal format: {value_str}"))
584 })?;
585
586 let div = i256::from_i128(10_i128).pow_checked((decimals.len() - scale) as u32)?;
587
588 let half = div.div_wrapping(i256::from_i128(2));
589 let half_neg = half.neg_wrapping();
590
591 let d = decimal_number.div_wrapping(div);
592 let r = decimal_number.mod_wrapping(div);
593
594 let adjusted = match decimal_number >= i256::ZERO {
596 true if r >= half => d.add_wrapping(i256::ONE),
597 false if r <= half_neg => d.sub_wrapping(i256::ONE),
598 _ => d,
599 };
600
601 let integers = if !integers.is_empty() {
602 i256::from_string(integers)
603 .ok_or_else(|| {
604 ArrowError::InvalidArgumentError(format!(
605 "Cannot parse decimal format: {value_str}"
606 ))
607 })
608 .map(|v| v.mul_wrapping(i256::from_i128(10_i128).pow_wrapping(scale as u32)))?
609 } else {
610 i256::ZERO
611 };
612
613 format!("{}", integers.add_wrapping(adjusted))
614 } else {
615 let padding = if scale > decimals.len() { scale } else { 0 };
616
617 let decimals = format!("{decimals:0<padding$}");
618 format!("{integers}{decimals}")
619 };
620
621 if negative {
622 number_decimals.insert(0, '-');
623 }
624
625 let value = i256::from_string(number_decimals.as_str()).ok_or_else(|| {
626 ArrowError::InvalidArgumentError(format!(
627 "Cannot convert {} to {}: Overflow",
628 value_str,
629 T::PREFIX
630 ))
631 })?;
632
633 T::Native::from_decimal(value).ok_or_else(|| {
634 ArrowError::InvalidArgumentError(format!("Cannot convert {} to {}", value_str, T::PREFIX))
635 })
636}
637
638pub(crate) fn generic_string_to_decimal_cast<'a, T, S>(
639 from: &'a S,
640 precision: u8,
641 scale: i8,
642 cast_options: &CastOptions,
643) -> Result<PrimitiveArray<T>, ArrowError>
644where
645 T: DecimalType,
646 T::Native: DecimalCast + ArrowNativeTypeOp,
647 &'a S: StringArrayType<'a>,
648{
649 if cast_options.safe {
650 let iter = from.iter().map(|v| {
651 v.and_then(|v| parse_string_to_decimal_native::<T>(v, scale as usize).ok())
652 .and_then(|v| T::is_valid_decimal_precision(v, precision).then_some(v))
653 });
654 Ok(unsafe {
659 PrimitiveArray::<T>::from_trusted_len_iter(iter)
660 .with_precision_and_scale(precision, scale)?
661 })
662 } else {
663 let vec = from
664 .iter()
665 .map(|v| {
666 v.map(|v| {
667 parse_string_to_decimal_native::<T>(v, scale as usize)
668 .map_err(|_| {
669 ArrowError::CastError(format!(
670 "Cannot cast string '{v}' to value of {} type",
671 T::DATA_TYPE,
672 ))
673 })
674 .and_then(|v| {
675 T::validate_decimal_precision(v, precision, scale).map(|()| v)
676 })
677 })
678 .transpose()
679 })
680 .collect::<Result<Vec<_>, _>>()?;
681 Ok(unsafe {
686 PrimitiveArray::<T>::from_trusted_len_iter(vec.iter())
687 .with_precision_and_scale(precision, scale)?
688 })
689 }
690}
691
692pub(crate) fn string_to_decimal_cast<T, Offset: OffsetSizeTrait>(
693 from: &GenericStringArray<Offset>,
694 precision: u8,
695 scale: i8,
696 cast_options: &CastOptions,
697) -> Result<PrimitiveArray<T>, ArrowError>
698where
699 T: DecimalType,
700 T::Native: DecimalCast + ArrowNativeTypeOp,
701{
702 generic_string_to_decimal_cast::<T, GenericStringArray<Offset>>(
703 from,
704 precision,
705 scale,
706 cast_options,
707 )
708}
709
710pub(crate) fn string_view_to_decimal_cast<T>(
711 from: &StringViewArray,
712 precision: u8,
713 scale: i8,
714 cast_options: &CastOptions,
715) -> Result<PrimitiveArray<T>, ArrowError>
716where
717 T: DecimalType,
718 T::Native: DecimalCast + ArrowNativeTypeOp,
719{
720 generic_string_to_decimal_cast::<T, StringViewArray>(from, precision, scale, cast_options)
721}
722
723pub(crate) fn cast_string_to_decimal<T, Offset: OffsetSizeTrait>(
725 from: &dyn Array,
726 precision: u8,
727 scale: i8,
728 cast_options: &CastOptions,
729) -> Result<ArrayRef, ArrowError>
730where
731 T: DecimalType,
732 T::Native: DecimalCast + ArrowNativeTypeOp,
733{
734 if scale < 0 {
735 return Err(ArrowError::InvalidArgumentError(format!(
736 "Cannot cast string to decimal with negative scale {scale}"
737 )));
738 }
739
740 if scale > T::MAX_SCALE {
741 return Err(ArrowError::InvalidArgumentError(format!(
742 "Cannot cast string to decimal greater than maximum scale {}",
743 T::MAX_SCALE
744 )));
745 }
746
747 let result = match from.data_type() {
748 DataType::Utf8View => string_view_to_decimal_cast::<T>(
749 from.as_any().downcast_ref::<StringViewArray>().unwrap(),
750 precision,
751 scale,
752 cast_options,
753 )?,
754 DataType::Utf8 | DataType::LargeUtf8 => string_to_decimal_cast::<T, Offset>(
755 from.as_any()
756 .downcast_ref::<GenericStringArray<Offset>>()
757 .unwrap(),
758 precision,
759 scale,
760 cast_options,
761 )?,
762 other => {
763 return Err(ArrowError::ComputeError(format!(
764 "Cannot cast {other:?} to decimal",
765 )));
766 }
767 };
768
769 Ok(Arc::new(result))
770}
771
772pub(crate) fn cast_floating_point_to_decimal<T: ArrowPrimitiveType, D>(
773 array: &PrimitiveArray<T>,
774 precision: u8,
775 scale: i8,
776 cast_options: &CastOptions,
777) -> Result<ArrayRef, ArrowError>
778where
779 <T as ArrowPrimitiveType>::Native: AsPrimitive<f64>,
780 D: DecimalType + ArrowPrimitiveType,
781 <D as ArrowPrimitiveType>::Native: DecimalCast,
782{
783 let mul = 10_f64.powi(scale as i32);
784
785 if cast_options.safe {
786 array
787 .unary_opt::<_, D>(|v| {
788 single_float_to_decimal::<D>(v.as_(), mul)
789 .filter(|v| D::is_valid_decimal_precision(*v, precision))
790 })
791 .with_precision_and_scale(precision, scale)
792 .map(|a| Arc::new(a) as ArrayRef)
793 } else {
794 array
795 .try_unary::<_, D, _>(|v| {
796 single_float_to_decimal::<D>(v.as_(), mul)
797 .ok_or_else(|| {
798 ArrowError::CastError(format!(
799 "Cannot cast to {}({}, {}). Overflowing on {:?}",
800 D::PREFIX,
801 precision,
802 scale,
803 v
804 ))
805 })
806 .and_then(|v| D::validate_decimal_precision(v, precision, scale).map(|()| v))
807 })?
808 .with_precision_and_scale(precision, scale)
809 .map(|a| Arc::new(a) as ArrayRef)
810 }
811}
812
813#[inline(always)]
816pub fn single_float_to_decimal<D>(input: f64, mul: f64) -> Option<D::Native>
817where
818 D: DecimalType + ArrowPrimitiveType,
819 <D as ArrowPrimitiveType>::Native: DecimalCast,
820{
821 D::Native::from_f64((mul * input).round())
822}
823
824pub(crate) fn cast_decimal_to_integer<D, T>(
825 array: &dyn Array,
826 base: D::Native,
827 scale: i8,
828 cast_options: &CastOptions,
829) -> Result<ArrayRef, ArrowError>
830where
831 T: ArrowPrimitiveType,
832 <T as ArrowPrimitiveType>::Native: NumCast,
833 D: DecimalType + ArrowPrimitiveType,
834 <D as ArrowPrimitiveType>::Native: ToPrimitive,
835{
836 let array = array.as_primitive::<D>();
837
838 let div: D::Native = base.pow_checked(scale.unsigned_abs() as u32).map_err(|_| {
839 ArrowError::CastError(format!(
840 "Cannot cast to {:?}. The scale {} causes overflow.",
841 D::PREFIX,
842 scale,
843 ))
844 })?;
845
846 let mut value_builder = PrimitiveBuilder::<T>::with_capacity(array.len());
847
848 if scale < 0 {
849 match cast_options.safe {
850 true => {
851 for i in 0..array.len() {
852 if array.is_null(i) {
853 value_builder.append_null();
854 } else {
855 let v = array
856 .value(i)
857 .mul_checked(div)
858 .ok()
859 .and_then(<T::Native as NumCast>::from::<D::Native>);
860 value_builder.append_option(v);
861 }
862 }
863 }
864 false => {
865 for i in 0..array.len() {
866 if array.is_null(i) {
867 value_builder.append_null();
868 } else {
869 let v = array.value(i).mul_checked(div)?;
870
871 let value =
872 <T::Native as NumCast>::from::<D::Native>(v).ok_or_else(|| {
873 ArrowError::CastError(format!(
874 "value of {:?} is out of range {}",
875 v,
876 T::DATA_TYPE
877 ))
878 })?;
879
880 value_builder.append_value(value);
881 }
882 }
883 }
884 }
885 } else {
886 match cast_options.safe {
887 true => {
888 for i in 0..array.len() {
889 if array.is_null(i) {
890 value_builder.append_null();
891 } else {
892 let v = array
893 .value(i)
894 .div_checked(div)
895 .ok()
896 .and_then(<T::Native as NumCast>::from::<D::Native>);
897 value_builder.append_option(v);
898 }
899 }
900 }
901 false => {
902 for i in 0..array.len() {
903 if array.is_null(i) {
904 value_builder.append_null();
905 } else {
906 let v = array.value(i).div_checked(div)?;
907
908 let value =
909 <T::Native as NumCast>::from::<D::Native>(v).ok_or_else(|| {
910 ArrowError::CastError(format!(
911 "value of {:?} is out of range {}",
912 v,
913 T::DATA_TYPE
914 ))
915 })?;
916
917 value_builder.append_value(value);
918 }
919 }
920 }
921 }
922 }
923 Ok(Arc::new(value_builder.finish()))
924}
925
926pub(crate) fn cast_decimal_to_float<D: DecimalType, T: ArrowPrimitiveType, F>(
932 array: &dyn Array,
933 op: F,
934) -> Result<ArrayRef, ArrowError>
935where
936 F: Fn(D::Native) -> T::Native,
937{
938 let array = array.as_primitive::<D>();
939 let array = array.unary::<_, T>(op);
940 Ok(Arc::new(array))
941}
942
943#[cfg(test)]
944mod tests {
945 use super::*;
946
947 #[test]
948 fn test_parse_string_to_decimal_native() -> Result<(), ArrowError> {
949 assert_eq!(
950 parse_string_to_decimal_native::<Decimal128Type>("0", 0)?,
951 0_i128
952 );
953 assert_eq!(
954 parse_string_to_decimal_native::<Decimal128Type>("0", 5)?,
955 0_i128
956 );
957
958 assert_eq!(
959 parse_string_to_decimal_native::<Decimal128Type>("123", 0)?,
960 123_i128
961 );
962 assert_eq!(
963 parse_string_to_decimal_native::<Decimal128Type>("123", 5)?,
964 12300000_i128
965 );
966
967 assert_eq!(
968 parse_string_to_decimal_native::<Decimal128Type>("123.45", 0)?,
969 123_i128
970 );
971 assert_eq!(
972 parse_string_to_decimal_native::<Decimal128Type>("123.45", 5)?,
973 12345000_i128
974 );
975
976 assert_eq!(
977 parse_string_to_decimal_native::<Decimal128Type>("123.4567891", 0)?,
978 123_i128
979 );
980 assert_eq!(
981 parse_string_to_decimal_native::<Decimal128Type>("123.4567891", 5)?,
982 12345679_i128
983 );
984
985 for value in ["", " ", ".", "+", "-", "+.", "-."] {
986 assert!(
987 parse_string_to_decimal_native::<Decimal128Type>(value, 2).is_err(),
988 "expected {value:?} to fail parsing as Decimal128"
989 );
990 assert!(
991 parse_string_to_decimal_native::<Decimal256Type>(value, 2).is_err(),
992 "expected {value:?} to fail parsing as Decimal256"
993 );
994 }
995 Ok(())
996 }
997
998 #[test]
999 fn test_rescale_decimal_upscale_within_precision() {
1000 let result = rescale_decimal::<Decimal128Type, Decimal128Type>(
1001 12_345_i128, 5,
1003 2,
1004 8,
1005 5,
1006 );
1007 assert_eq!(result, Some(12_345_000_i128));
1008 }
1009
1010 #[test]
1011 fn test_rescale_decimal_downscale_rounds_half_away_from_zero() {
1012 let positive = rescale_decimal::<Decimal128Type, Decimal128Type>(
1013 1_050_i128, 5, 3, 5, 1,
1015 );
1016 assert_eq!(positive, Some(11_i128)); let negative = rescale_decimal::<Decimal128Type, Decimal128Type>(
1019 -1_050_i128, 5,
1021 3,
1022 5,
1023 1,
1024 );
1025 assert_eq!(negative, Some(-11_i128)); }
1027
1028 #[test]
1029 fn test_rescale_decimal_downscale_large_delta_returns_zero() {
1030 let result = rescale_decimal::<Decimal32Type, Decimal32Type>(12_345_i32, 9, 9, 9, 4);
1031 assert_eq!(result, Some(0_i32));
1032 }
1033
1034 #[test]
1035 fn test_rescale_decimal_upscale_overflow_returns_none() {
1036 let result = rescale_decimal::<Decimal32Type, Decimal32Type>(9_999_i32, 4, 0, 5, 2);
1037 assert_eq!(result, None);
1038 }
1039
1040 #[test]
1041 fn test_rescale_decimal_invalid_input_precision_scale_returns_none() {
1042 let result = rescale_decimal::<Decimal128Type, Decimal128Type>(123_i128, 39, 39, 38, 38);
1043 assert_eq!(result, None);
1044 }
1045
1046 #[test]
1047 fn test_rescale_decimal_invalid_output_precision_scale_returns_none() {
1048 let result = rescale_decimal::<Decimal128Type, Decimal128Type>(123_i128, 38, 38, 39, 39);
1049 assert_eq!(result, None);
1050 }
1051}