@@ -69,10 +69,7 @@ pub fn can_cast_types(from_type: &DataType, to_type: &DataType) -> bool {
69
69
70
70
match ( from_type, to_type) {
71
71
// TODO now just support signed numeric to decimal, support decimal to numeric later
72
- // support one decimal data type to another decimal data type
73
- // or UTF-8 to decimal
74
- // numeric to decimal
75
- ( Int8 | Int16 | Int32 | Int64 | Float32 | Float64 | Decimal ( _, _) , Decimal ( _, _) )
72
+ ( Int8 | Int16 | Int32 | Int64 | Float32 | Float64 , Decimal ( _, _) )
76
73
| (
77
74
Null ,
78
75
Boolean
@@ -245,6 +242,45 @@ pub fn cast(array: &ArrayRef, to_type: &DataType) -> Result<ArrayRef> {
245
242
cast_with_options ( array, to_type, & DEFAULT_CAST_OPTIONS )
246
243
}
247
244
245
+ // cast the integer array to defined decimal data type array
246
+ macro_rules! cast_integer_to_decimal {
247
+ ( $ARRAY: expr, $ARRAY_TYPE: ident, $PRECISION : ident, $SCALE : ident) => { {
248
+ let mut decimal_builder = DecimalBuilder :: new( $ARRAY. len( ) , * $PRECISION, * $SCALE) ;
249
+ let array = $ARRAY. as_any( ) . downcast_ref:: <$ARRAY_TYPE>( ) . unwrap( ) ;
250
+ let mul: i128 = 10_i128 . pow( * $SCALE as u32 ) ;
251
+ for i in 0 ..array. len( ) {
252
+ if array. is_null( i) {
253
+ decimal_builder. append_null( ) ?;
254
+ } else {
255
+ // convert i128 first
256
+ let v = array. value( i) as i128 ;
257
+ // if the input value is overflow, it will throw an error.
258
+ decimal_builder. append_value( mul * v) ?;
259
+ }
260
+ }
261
+ Ok ( Arc :: new( decimal_builder. finish( ) ) )
262
+ } } ;
263
+ }
264
+
265
+ // cast the floating-point array to defined decimal data type array
266
+ macro_rules! cast_floating_point_to_decimal {
267
+ ( $ARRAY: expr, $ARRAY_TYPE: ident, $PRECISION : ident, $SCALE : ident) => { {
268
+ let mut decimal_builder = DecimalBuilder :: new( $ARRAY. len( ) , * $PRECISION, * $SCALE) ;
269
+ let array = $ARRAY. as_any( ) . downcast_ref:: <$ARRAY_TYPE>( ) . unwrap( ) ;
270
+ let mul = 10_f64 . powi( * $SCALE as i32 ) ;
271
+ for i in 0 ..array. len( ) {
272
+ if array. is_null( i) {
273
+ decimal_builder. append_null( ) ?;
274
+ } else {
275
+ let v = ( ( array. value( i) as f64 ) * mul) as i128 ;
276
+ // if the input value is overflow, it will throw an error.
277
+ decimal_builder. append_value( v) ?;
278
+ }
279
+ }
280
+ Ok ( Arc :: new( decimal_builder. finish( ) ) )
281
+ } } ;
282
+ }
283
+
248
284
/// Cast `array` to the provided data type and return a new Array with
249
285
/// type `to_type`, if possible. It accepts `CastOptions` to allow consumers
250
286
/// to configure cast behavior.
@@ -279,6 +315,34 @@ pub fn cast_with_options(
279
315
return Ok ( array. clone ( ) ) ;
280
316
}
281
317
match ( from_type, to_type) {
318
+ ( _, Decimal ( precision, scale) ) => {
319
+ // cast data to decimal
320
+ match from_type {
321
+ // TODO now just support signed numeric to decimal, support decimal to numeric later
322
+ Int8 => {
323
+ cast_integer_to_decimal ! ( array, Int8Array , precision, scale)
324
+ }
325
+ Int16 => {
326
+ cast_integer_to_decimal ! ( array, Int16Array , precision, scale)
327
+ }
328
+ Int32 => {
329
+ cast_integer_to_decimal ! ( array, Int32Array , precision, scale)
330
+ }
331
+ Int64 => {
332
+ cast_integer_to_decimal ! ( array, Int64Array , precision, scale)
333
+ }
334
+ Float32 => {
335
+ cast_floating_point_to_decimal ! ( array, Float32Array , precision, scale)
336
+ }
337
+ Float64 => {
338
+ cast_floating_point_to_decimal ! ( array, Float64Array , precision, scale)
339
+ }
340
+ _ => Err ( ArrowError :: CastError ( format ! (
341
+ "Casting from {:?} to {:?} not supported" ,
342
+ from_type, to_type
343
+ ) ) ) ,
344
+ }
345
+ }
282
346
(
283
347
Null ,
284
348
Boolean
@@ -1257,7 +1321,7 @@ fn cast_string_to_date64<Offset: StringOffsetSizeTrait>(
1257
1321
if string_array. is_null ( i) {
1258
1322
Ok ( None )
1259
1323
} else {
1260
- let string = string_array
1324
+ let string = string_array
1261
1325
. value ( i) ;
1262
1326
1263
1327
let result = string
@@ -1476,7 +1540,7 @@ fn dictionary_cast<K: ArrowDictionaryKeyType>(
1476
1540
return Err ( ArrowError :: CastError ( format ! (
1477
1541
"Unsupported type {:?} for dictionary index" ,
1478
1542
to_index_type
1479
- ) ) )
1543
+ ) ) ) ;
1480
1544
}
1481
1545
} ;
1482
1546
@@ -1842,6 +1906,125 @@ where
1842
1906
mod tests {
1843
1907
use super :: * ;
1844
1908
use crate :: { buffer:: Buffer , util:: display:: array_value_to_string} ;
1909
+ use num:: traits:: Pow ;
1910
+
1911
+ #[ test]
1912
+ fn test_cast_numeric_to_decimal ( ) {
1913
+ let data_types = vec ! [
1914
+ DataType :: Int8 ,
1915
+ DataType :: Int16 ,
1916
+ DataType :: Int32 ,
1917
+ DataType :: Int64 ,
1918
+ DataType :: Float32 ,
1919
+ DataType :: Float64 ,
1920
+ ] ;
1921
+ let decimal_type = DataType :: Decimal ( 38 , 6 ) ;
1922
+ for data_type in data_types {
1923
+ assert ! ( can_cast_types( & data_type, & decimal_type) )
1924
+ }
1925
+ assert ! ( !can_cast_types( & DataType :: UInt64 , & decimal_type) ) ;
1926
+
1927
+ // test i8 to decimal type
1928
+ let array = Int8Array :: from ( vec ! [ 1 , 2 , 3 , 4 , 5 ] ) ;
1929
+ let array = Arc :: new ( array) as ArrayRef ;
1930
+ let casted_array = cast ( & array, & decimal_type) . unwrap ( ) ;
1931
+ let decimal_array = casted_array
1932
+ . as_any ( )
1933
+ . downcast_ref :: < DecimalArray > ( )
1934
+ . unwrap ( ) ;
1935
+ assert_eq ! ( & decimal_type, decimal_array. data_type( ) ) ;
1936
+ for i in 0 ..array. len ( ) {
1937
+ assert_eq ! (
1938
+ 10_i128 . pow( 6 ) * ( i as i128 + 1 ) ,
1939
+ decimal_array. value( i as usize )
1940
+ ) ;
1941
+ }
1942
+ // test i8 to decimal type with overflow the result type
1943
+ // the 100 will be converted to 1000_i128, but it is out of range for max value in the precision 3.
1944
+ let array = Int8Array :: from ( vec ! [ 1 , 2 , 3 , 4 , 100 ] ) ;
1945
+ let array = Arc :: new ( array) as ArrayRef ;
1946
+ let casted_array = cast ( & array, & DataType :: Decimal ( 3 , 1 ) ) ;
1947
+ assert ! ( casted_array. is_err( ) ) ;
1948
+ assert_eq ! ( "Invalid argument error: The value of 1000 i128 is not compatible with Decimal(3,1)" , casted_array. unwrap_err( ) . to_string( ) ) ;
1949
+
1950
+ // test i16 to decimal type
1951
+ let array = Int16Array :: from ( vec ! [ 1 , 2 , 3 , 4 , 5 ] ) ;
1952
+ let array = Arc :: new ( array) as ArrayRef ;
1953
+ let casted_array = cast ( & array, & decimal_type) . unwrap ( ) ;
1954
+ let decimal_array = casted_array
1955
+ . as_any ( )
1956
+ . downcast_ref :: < DecimalArray > ( )
1957
+ . unwrap ( ) ;
1958
+ assert_eq ! ( & decimal_type, decimal_array. data_type( ) ) ;
1959
+ for i in 0 ..array. len ( ) {
1960
+ assert_eq ! (
1961
+ 10_i128 . pow( 6 ) * ( i as i128 + 1 ) ,
1962
+ decimal_array. value( i as usize )
1963
+ ) ;
1964
+ }
1965
+
1966
+ // test i32 to decimal type
1967
+ let array = Int32Array :: from ( vec ! [ 1 , 2 , 3 , 4 , 5 ] ) ;
1968
+ let array = Arc :: new ( array) as ArrayRef ;
1969
+ let casted_array = cast ( & array, & decimal_type) . unwrap ( ) ;
1970
+ let decimal_array = casted_array
1971
+ . as_any ( )
1972
+ . downcast_ref :: < DecimalArray > ( )
1973
+ . unwrap ( ) ;
1974
+ assert_eq ! ( & decimal_type, decimal_array. data_type( ) ) ;
1975
+ for i in 0 ..array. len ( ) {
1976
+ assert_eq ! (
1977
+ 10_i128 . pow( 6 ) * ( i as i128 + 1 ) ,
1978
+ decimal_array. value( i as usize )
1979
+ ) ;
1980
+ }
1981
+
1982
+ // test i64 to decimal type
1983
+ let array = Int64Array :: from ( vec ! [ 1 , 2 , 3 , 4 , 5 ] ) ;
1984
+ let array = Arc :: new ( array) as ArrayRef ;
1985
+ let casted_array = cast ( & array, & decimal_type) . unwrap ( ) ;
1986
+ let decimal_array = casted_array
1987
+ . as_any ( )
1988
+ . downcast_ref :: < DecimalArray > ( )
1989
+ . unwrap ( ) ;
1990
+ assert_eq ! ( & decimal_type, decimal_array. data_type( ) ) ;
1991
+ for i in 0 ..array. len ( ) {
1992
+ assert_eq ! (
1993
+ 10_i128 . pow( 6 ) * ( i as i128 + 1 ) ,
1994
+ decimal_array. value( i as usize )
1995
+ ) ;
1996
+ }
1997
+
1998
+ // test f32 to decimal type
1999
+ let f_data: Vec < f32 > = vec ! [ 1.1 , 2.2 , 4.4 , 1.1234567891234 ] ;
2000
+ let array = Float32Array :: from ( f_data. clone ( ) ) ;
2001
+ let array = Arc :: new ( array) as ArrayRef ;
2002
+ let casted_array = cast ( & array, & decimal_type) . unwrap ( ) ;
2003
+ let decimal_array = casted_array
2004
+ . as_any ( )
2005
+ . downcast_ref :: < DecimalArray > ( )
2006
+ . unwrap ( ) ;
2007
+ assert_eq ! ( & decimal_type, decimal_array. data_type( ) ) ;
2008
+ for i in 0 ..array. len ( ) {
2009
+ let left = ( f_data[ i] as f64 ) * 10_f64 . pow ( 6 ) ;
2010
+ assert_eq ! ( left as i128 , decimal_array. value( i as usize ) ) ;
2011
+ }
2012
+
2013
+ // test f64 to decimal type
2014
+ let f_data: Vec < f64 > = vec ! [ 1.1 , 2.2 , 4.4 , 1.1234567891234 ] ;
2015
+ let array = Float64Array :: from ( f_data. clone ( ) ) ;
2016
+ let array = Arc :: new ( array) as ArrayRef ;
2017
+ let casted_array = cast ( & array, & decimal_type) . unwrap ( ) ;
2018
+ let decimal_array = casted_array
2019
+ . as_any ( )
2020
+ . downcast_ref :: < DecimalArray > ( )
2021
+ . unwrap ( ) ;
2022
+ assert_eq ! ( & decimal_type, decimal_array. data_type( ) ) ;
2023
+ for i in 0 ..array. len ( ) {
2024
+ let left = ( f_data[ i] as f64 ) * 10_f64 . pow ( 6 ) ;
2025
+ assert_eq ! ( left as i128 , decimal_array. value( i as usize ) ) ;
2026
+ }
2027
+ }
1845
2028
1846
2029
#[ test]
1847
2030
fn test_cast_i32_to_f64 ( ) {
0 commit comments