@@ -69,7 +69,8 @@ pub fn can_cast_types(from_type: &DataType, to_type: &DataType) -> bool {
69
69
70
70
match ( from_type, to_type) {
71
71
// TODO UTF8/unsigned numeric to decimal
72
- // TODO decimal to decimal type
72
+ // cast one decimal type to another decimal type
73
+ ( Decimal ( _, _) , Decimal ( _, _) ) => true ,
73
74
// signed numeric to decimal
74
75
( Int8 | Int16 | Int32 | Int64 | Float32 | Float64 , Decimal ( _, _) ) |
75
76
// decimal to signed numeric
@@ -371,6 +372,7 @@ pub fn cast_with_options(
371
372
return Ok ( array. clone ( ) ) ;
372
373
}
373
374
match ( from_type, to_type) {
375
+ ( Decimal ( _, s1) , Decimal ( p2, s2) ) => cast_decimal_to_decimal ( array, s1, p2, s2) ,
374
376
( Decimal ( _, scale) , _) => {
375
377
// cast decimal to other type
376
378
match to_type {
@@ -1139,6 +1141,42 @@ const MILLISECONDS_IN_DAY: i64 = SECONDS_IN_DAY * MILLISECONDS;
1139
1141
/// Number of days between 0001-01-01 and 1970-01-01
1140
1142
const EPOCH_DAYS_FROM_CE : i32 = 719_163 ;
1141
1143
1144
+ /// Cast one type of decimal array to another type of decimal array
1145
+ fn cast_decimal_to_decimal (
1146
+ array : & ArrayRef ,
1147
+ input_scale : & usize ,
1148
+ output_precision : & usize ,
1149
+ output_scale : & usize ,
1150
+ ) -> Result < ArrayRef > {
1151
+ let mut decimal_builder =
1152
+ DecimalBuilder :: new ( array. len ( ) , * output_precision, * output_scale) ;
1153
+ let array = array. as_any ( ) . downcast_ref :: < DecimalArray > ( ) . unwrap ( ) ;
1154
+ if input_scale > output_scale {
1155
+ // For example, input_scale is 4 and output_scale is 3;
1156
+ // Original value is 11234_i128, and will be cast to 1123_i128.
1157
+ let div = 10_i128 . pow ( ( input_scale - output_scale) as u32 ) ;
1158
+ for i in 0 ..array. len ( ) {
1159
+ if array. is_null ( i) {
1160
+ decimal_builder. append_null ( ) ?;
1161
+ } else {
1162
+ decimal_builder. append_value ( array. value ( i) / div) ?;
1163
+ }
1164
+ }
1165
+ } else {
1166
+ // For example, input_scale is 3 and output_scale is 4;
1167
+ // Original value is 1123_i128, and will be cast to 11230_i128.
1168
+ let mul = 10_i128 . pow ( ( output_scale - input_scale) as u32 ) ;
1169
+ for i in 0 ..array. len ( ) {
1170
+ if array. is_null ( i) {
1171
+ decimal_builder. append_null ( ) ?;
1172
+ } else {
1173
+ decimal_builder. append_value ( array. value ( i) * mul) ?;
1174
+ }
1175
+ }
1176
+ }
1177
+ Ok ( Arc :: new ( decimal_builder. finish ( ) ) )
1178
+ }
1179
+
1142
1180
/// Cast an array by changing its array_data type to the desired type
1143
1181
///
1144
1182
/// Arrays should have the same primitive data type, otherwise this should fail.
@@ -2035,6 +2073,34 @@ mod tests {
2035
2073
Ok ( decimal_builder. finish ( ) )
2036
2074
}
2037
2075
2076
+ #[ test]
2077
+ fn test_cast_decimal_to_decimal ( ) {
2078
+ let input_type = DataType :: Decimal ( 20 , 3 ) ;
2079
+ let output_type = DataType :: Decimal ( 20 , 4 ) ;
2080
+ assert ! ( can_cast_types( & input_type, & output_type) ) ;
2081
+ let array = vec ! [ Some ( 1123456 ) , Some ( 2123456 ) , Some ( 3123456 ) , None ] ;
2082
+ let input_decimal_array = create_decimal_array ( & array, 20 , 3 ) . unwrap ( ) ;
2083
+ let array = Arc :: new ( input_decimal_array) as ArrayRef ;
2084
+ generate_cast_test_case ! (
2085
+ & array,
2086
+ DecimalArray ,
2087
+ & output_type,
2088
+ vec![
2089
+ Some ( 11234560_i128 ) ,
2090
+ Some ( 21234560_i128 ) ,
2091
+ Some ( 31234560_i128 ) ,
2092
+ None
2093
+ ]
2094
+ ) ;
2095
+ // negative test
2096
+ let array = vec ! [ Some ( 123456 ) , None ] ;
2097
+ let input_decimal_array = create_decimal_array ( & array, 10 , 0 ) . unwrap ( ) ;
2098
+ let array = Arc :: new ( input_decimal_array) as ArrayRef ;
2099
+ let result = cast ( & array, & DataType :: Decimal ( 2 , 2 ) ) ;
2100
+ assert ! ( result. is_err( ) ) ;
2101
+ assert_eq ! ( "Invalid argument error: The value of 12345600 i128 is not compatible with Decimal(2,2)" . to_string( ) , result. unwrap_err( ) . to_string( ) ) ;
2102
+ }
2103
+
2038
2104
#[ test]
2039
2105
fn test_cast_decimal_to_numeric ( ) {
2040
2106
let decimal_type = DataType :: Decimal ( 38 , 2 ) ;
0 commit comments