## Coverage Report

#### Created: 2025-11-22 06:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)

    /Users/andrewlamb/Software/datafusion/datafusion/physical-expr/src/expressions/cast.rs

    Line
    Count
    Source
    1
    // Licensed to the Apache Software Foundation (ASF) under one
    2
    // or more contributor license agreements.  See the NOTICE file
    3
    // distributed with this work for additional information
    4
    // regarding copyright ownership.  The ASF licenses this file
    5
    // to you under the Apache License, Version 2.0 (the
    6
    // "License"); you may not use this file except in compliance
    7
    // with the License.  You may obtain a copy of the License at
    8
    //
    9
    //   http://www.apache.org/licenses/LICENSE-2.0
    10
    //
    11
    // Unless required by applicable law or agreed to in writing,
    12
    // software distributed under the License is distributed on an
    13
    // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    14
    // KIND, either express or implied.  See the License for the
    15
    // specific language governing permissions and limitations
    16
    // under the License.
    17
    18
    use std::any::Any;
    19
    use std::fmt;
    20
    use std::hash::Hash;
    21
    use std::sync::Arc;
    22
    23
    use crate::physical_expr::PhysicalExpr;
    24
    25
    use arrow::compute::{can_cast_types, CastOptions};
    26
    use arrow::datatypes::{DataType, DataType::*, FieldRef, Schema};
    27
    use arrow::record_batch::RecordBatch;
    28
    use datafusion_common::format::DEFAULT_FORMAT_OPTIONS;
    29
    use datafusion_common::{not_impl_err, Result};
    30
    use datafusion_expr_common::columnar_value::ColumnarValue;
    31
    use datafusion_expr_common::interval_arithmetic::Interval;
    32
    use datafusion_expr_common::sort_properties::ExprProperties;
    33
    34
    const DEFAULT_CAST_OPTIONS: CastOptions<'static> = CastOptions {
    35
        safe: false,
    36
        format_options: DEFAULT_FORMAT_OPTIONS,
    37
    };
    38
    39
    const DEFAULT_SAFE_CAST_OPTIONS: CastOptions<'static> = CastOptions {
    40
        safe: true,
    41
        format_options: DEFAULT_FORMAT_OPTIONS,
    42
    };
    43
    44
    /// CAST expression casts an expression to a specific data type and returns a runtime error on invalid cast
    45
    #[derive(Debug, Clone, Eq)]
    46
    pub struct CastExpr {
    47
        /// The expression to cast
    48
        pub expr: Arc<dyn PhysicalExpr>,
    49
        /// The data type to cast to
    50
        cast_type: DataType,
    51
        /// Cast options
    52
        cast_options: CastOptions<'static>,
    53
    }
    54
    55
    // Manually derive PartialEq and Hash to work around https://github.com/rust-lang/rust/issues/78808
    56
    impl PartialEq for CastExpr {
    57
    0
        fn eq(&self, other: &Self) -> bool {
    58
    0
            self.expr.eq(&other.expr)
    59
    0
                && self.cast_type.eq(&other.cast_type)
    60
    0
                && self.cast_options.eq(&other.cast_options)
    61
    0
        }
    62
    }
    63
    64
    impl Hash for CastExpr {
    65
    0
        fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
    66
    0
            self.expr.hash(state);
    67
    0
            self.cast_type.hash(state);
    68
    0
            self.cast_options.hash(state);
    69
    0
        }
    70
    }
    71
    72
    impl CastExpr {
    73
        /// Create a new CastExpr
    74
    4
        pub fn new(
    75
    4
            expr: Arc<dyn PhysicalExpr>,
    76
    4
            cast_type: DataType,
    77
    4
            cast_options: Option<CastOptions<'static>>,
    78
    4
        ) -> Self {
    79
    4
            Self {
    80
    4
                expr,
    81
    4
                cast_type,
    82
    4
                cast_options: cast_options.unwrap_or(DEFAULT_CAST_OPTIONS),
    83
    4
            }
    84
    4
        }
    85
    86
        /// The expression to cast
    87
    0
        pub fn expr(&self) -> &Arc<dyn PhysicalExpr> {
    88
    0
            &self.expr
    89
    0
        }
    90
    91
        /// The data type to cast to
    92
    0
        pub fn cast_type(&self) -> &DataType {
    93
    0
            &self.cast_type
    94
    0
        }
    95
    96
        /// The cast options
    97
    0
        pub fn cast_options(&self) -> &CastOptions<'static> {
    98
    0
            &self.cast_options
    99
    0
        }
    100
    101
        /// Check if the cast is a widening cast (e.g. from `Int8` to `Int16`).
    102
    0
        pub fn is_bigger_cast(&self, src: &DataType) -> bool {
    103
    0
            if self.cast_type.eq(src) {
    104
    0
                return true;
    105
    0
            }
    106
    0
            matches!(
    107
    0
                (src, &self.cast_type),
    108
                (Int8, Int16 | Int32 | Int64)
    109
                    | (Int16, Int32 | Int64)
    110
                    | (Int32, Int64)
    111
                    | (UInt8, UInt16 | UInt32 | UInt64)
    112
                    | (UInt16, UInt32 | UInt64)
    113
                    | (UInt32, UInt64)
    114
                    | (
    115
                        Int8 | Int16 | Int32 | UInt8 | UInt16 | UInt32,
    116
                        Float32 | Float64
    117
                    )
    118
                    | (Int64 | UInt64, Float64)
    119
                    | (Utf8, LargeUtf8)
    120
            )
    121
    0
        }
    122
    }
    123
    124
    impl fmt::Display for CastExpr {
    125
    0
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    126
    0
            write!(f, "CAST({} AS {:?})", self.expr, self.cast_type)
    127
    0
        }
    128
    }
    129
    130
    impl PhysicalExpr for CastExpr {
    131
        /// Return a reference to Any that can be used for downcasting
    132
    0
        fn as_any(&self) -> &dyn Any {
    133
    0
            self
    134
    0
        }
    135
    136
    2
        fn data_type(&self, _input_schema: &Schema) -> Result<DataType> {
    137
    2
            Ok(self.cast_type.clone())
    138
    2
        }
    139
    140
    0
        fn nullable(&self, input_schema: &Schema) -> Result<bool> {
    141
    0
            self.expr.nullable(input_schema)
    142
    0
        }
    143
    144
    8
        fn evaluate(&self, batch: &RecordBatch) -> Result<ColumnarValue> {
    145
    8
            let value = self.expr.evaluate(batch)?0;
    146
    8
            value.cast_to(&self.cast_type, Some(&self.cast_options))
    147
    8
        }
    148
    149
    0
        fn return_field(&self, input_schema: &Schema) -> Result<FieldRef> {
    150
    0
            Ok(self
    151
    0
                .expr
    152
    0
                .return_field(input_schema)?
    153
    0
                .as_ref()
    154
    0
                .clone()
    155
    0
                .with_data_type(self.cast_type.clone())
    156
    0
                .into())
    157
    0
        }
    158
    159
    0
        fn children(&self) -> Vec<&Arc<dyn PhysicalExpr>> {
    160
    0
            vec![&self.expr]
    161
    0
        }
    162
    163
    0
        fn with_new_children(
    164
    0
            self: Arc<Self>,
    165
    0
            children: Vec<Arc<dyn PhysicalExpr>>,
    166
    0
        ) -> Result<Arc<dyn PhysicalExpr>> {
    167
    0
            Ok(Arc::new(CastExpr::new(
    168
    0
                Arc::clone(&children[0]),
    169
    0
                self.cast_type.clone(),
    170
    0
                Some(self.cast_options.clone()),
    171
    0
            )))
    172
    0
        }
    173
    174
    0
        fn evaluate_bounds(&self, children: &[&Interval]) -> Result<Interval> {
    175
            // Cast current node's interval to the right type:
    176
    0
            children[0].cast_to(&self.cast_type, &self.cast_options)
    177
    0
        }
    178
    179
    0
        fn propagate_constraints(
    180
    0
            &self,
    181
    0
            interval: &Interval,
    182
    0
            children: &[&Interval],
    183
    0
        ) -> Result<Option<Vec<Interval>>> {
    184
    0
            let child_interval = children[0];
    185
            // Get child's datatype:
    186
    0
            let cast_type = child_interval.data_type();
    187
    0
            Ok(Some(vec![
    188
    0
                interval.cast_to(&cast_type, &DEFAULT_SAFE_CAST_OPTIONS)?
    189
            ]))
    190
    0
        }
    191
    192
        /// A [`CastExpr`] preserves the ordering of its child if the cast is done
    193
        /// under the same datatype family.
    194
    0
        fn get_properties(&self, children: &[ExprProperties]) -> Result<ExprProperties> {
    195
    0
            let source_datatype = children[0].range.data_type();
    196
    0
            let target_type = &self.cast_type;
    197
    198
    0
            let unbounded = Interval::make_unbounded(target_type)?;
    199
    0
            if (source_datatype.is_numeric() || source_datatype == Boolean)
    200
    0
                && target_type.is_numeric()
    201
    0
                || source_datatype.is_temporal() && target_type.is_temporal()
    202
    0
                || source_datatype.eq(target_type)
    203
            {
    204
    0
                Ok(children[0].clone().with_range(unbounded))
    205
            } else {
    206
    0
                Ok(ExprProperties::new_unknown().with_range(unbounded))
    207
            }
    208
    0
        }
    209
    210
    0
        fn fmt_sql(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
    211
    0
            write!(f, "CAST(")?;
    212
    0
            self.expr.fmt_sql(f)?;
    213
    0
            write!(f, " AS {:?}", self.cast_type)?;
    214
    215
    0
            write!(f, ")")
    216
    0
        }
    217
    }
    218
    219
    /// Return a PhysicalExpression representing `expr` casted to
    220
    /// `cast_type`, if any casting is needed.
    221
    ///
    222
    /// Note that such casts may lose type information
    223
    5
    pub fn cast_with_options(
    224
    5
        expr: Arc<dyn PhysicalExpr>,
    225
    5
        input_schema: &Schema,
    226
    5
        cast_type: DataType,
    227
    5
        cast_options: Option<CastOptions<'static>>,
    228
    5
    ) -> Result<Arc<dyn PhysicalExpr>> {
    229
    5
        let expr_type = expr.data_type(input_schema)?0;
    230
    5
        if expr_type == cast_type {
    231
    1
            Ok(Arc::clone(&expr))
    232
    4
        } else if can_cast_types(&expr_type, &cast_type) {
    233
    4
            Ok(Arc::new(CastExpr::new(expr, cast_type, cast_options)))
    234
        } else {
    235
    0
            not_impl_err!("Unsupported CAST from {expr_type} to {cast_type}")
    236
        }
    237
    5
    }
    238
    239
    /// Return a PhysicalExpression representing `expr` casted to
    240
    /// `cast_type`, if any casting is needed.
    241
    ///
    242
    /// Note that such casts may lose type information
    243
    5
    pub fn cast(
    244
    5
        expr: Arc<dyn PhysicalExpr>,
    245
    5
        input_schema: &Schema,
    246
    5
        cast_type: DataType,
    247
    5
    ) -> Result<Arc<dyn PhysicalExpr>> {
    248
    5
        cast_with_options(expr, input_schema, cast_type, None)
    249
    5
    }
    250
    251
    #[cfg(test)]
    252
    mod tests {
    253
        use super::*;
    254
    255
        use crate::expressions::column::col;
    256
    257
        use arrow::{
    258
            array::{
    259
                Array, Decimal128Array, Float32Array, Float64Array, Int16Array, Int32Array,
    260
                Int64Array, Int8Array, StringArray, Time64NanosecondArray,
    261
                TimestampNanosecondArray, UInt32Array,
    262
            },
    263
            datatypes::*,
    264
        };
    265
        use datafusion_physical_expr_common::physical_expr::fmt_sql;
    266
        use insta::assert_snapshot;
    267
    268
        // runs an end-to-end test of physical type cast
    269
        // 1. construct a record batch with a column "a" of type A
    270
        // 2. construct a physical expression of CAST(a AS B)
    271
        // 3. evaluate the expression
    272
        // 4. verify that the resulting expression is of type B
    273
        // 5. verify that the resulting values are downcastable and correct
    274
        macro_rules! generic_decimal_to_other_test_cast {
    275
            ($DECIMAL_ARRAY:ident, $A_TYPE:expr, $TYPEARRAY:ident, $TYPE:expr, $VEC:expr,$CAST_OPTIONS:expr) => {{
    276
                let schema = Schema::new(vec![Field::new("a", $A_TYPE, true)]);
    277
                let batch = RecordBatch::try_new(
    278
                    Arc::new(schema.clone()),
    279
                    vec![Arc::new($DECIMAL_ARRAY)],
    280
                )?;
    281
                // verify that we can construct the expression
    282
                let expression =
    283
                    cast_with_options(col("a", &schema)?, &schema, $TYPE, $CAST_OPTIONS)?;
    284
    285
                // verify that its display is correct
    286
                assert_eq!(
    287
                    format!("CAST(a@0 AS {:?})", $TYPE),
    288
                    format!("{}", expression)
    289
                );
    290
    291
                // verify that the expression's type is correct
    292
                assert_eq!(expression.data_type(&schema)?, $TYPE);
    293
    294
                // compute
    295
                let result = expression
    296
                    .evaluate(&batch)?
    297
                    .into_array(batch.num_rows())
    298
                    .expect("Failed to convert to array");
    299
    300
                // verify that the array's data_type is correct
    301
                assert_eq!(*result.data_type(), $TYPE);
    302
    303
                // verify that the data itself is downcastable
    304
                let result = result
    305
                    .as_any()
    306
                    .downcast_ref::<$TYPEARRAY>()
    307
                    .expect("failed to downcast");
    308
    309
                // verify that the result itself is correct
    310
                for (i, x) in $VEC.iter().enumerate() {
    311
                    match x {
    312
                        Some(x) => assert_eq!(result.value(i), *x),
    313
                        None => assert!(!result.is_valid(i)),
    314
                    }
    315
                }
    316
            }};
    317
        }
    318
    319
        // runs an end-to-end test of physical type cast
    320
        // 1. construct a record batch with a column "a" of type A
    321
        // 2. construct a physical expression of CAST(a AS B)
    322
        // 3. evaluate the expression
    323
        // 4. verify that the resulting expression is of type B
    324
        // 5. verify that the resulting values are downcastable and correct
    325
        macro_rules! generic_test_cast {
    326
            ($A_ARRAY:ident, $A_TYPE:expr, $A_VEC:expr, $TYPEARRAY:ident, $TYPE:expr, $VEC:expr, $CAST_OPTIONS:expr) => {{
    327
                let schema = Schema::new(vec![Field::new("a", $A_TYPE, true)]);
    328
                let a_vec_len = $A_VEC.len();
    329
                let a = $A_ARRAY::from($A_VEC);
    330
                let batch =
    331
                    RecordBatch::try_new(Arc::new(schema.clone()), vec![Arc::new(a)])?;
    332
    333
                // verify that we can construct the expression
    334
                let expression =
    335
                    cast_with_options(col("a", &schema)?, &schema, $TYPE, $CAST_OPTIONS)?;
    336
    337
                // verify that its display is correct
    338
                assert_eq!(
    339
                    format!("CAST(a@0 AS {:?})", $TYPE),
    340
                    format!("{}", expression)
    341
                );
    342
    343
                // verify that the expression's type is correct
    344
                assert_eq!(expression.data_type(&schema)?, $TYPE);
    345
    346
                // compute
    347
                let result = expression
    348
                    .evaluate(&batch)?
    349
                    .into_array(batch.num_rows())
    350
                    .expect("Failed to convert to array");
    351
    352
                // verify that the array's data_type is correct
    353
                assert_eq!(*result.data_type(), $TYPE);
    354
    355
                // verify that the len is correct
    356
                assert_eq!(result.len(), a_vec_len);
    357
    358
                // verify that the data itself is downcastable
    359
                let result = result
    360
                    .as_any()
    361
                    .downcast_ref::<$TYPEARRAY>()
    362
                    .expect("failed to downcast");
    363
    364
                // verify that the result itself is correct
    365
                for (i, x) in $VEC.iter().enumerate() {
    366
                    match x {
    367
                        Some(x) => assert_eq!(result.value(i), *x),
    368
                        None => assert!(!result.is_valid(i)),
    369
                    }
    370
                }
    371
            }};
    372
        }
    373
    374
        #[test]
    375
    0
        fn test_cast_decimal_to_decimal() -> Result<()> {
    376
    0
            let array = vec![
    377
    0
                Some(1234),
    378
    0
                Some(2222),
    379
    0
                Some(3),
    380
    0
                Some(4000),
    381
    0
                Some(5000),
    382
    0
                None,
    383
            ];
    384
    385
    0
            let decimal_array = array
    386
    0
                .clone()
    387
    0
                .into_iter()
    388
    0
                .collect::<Decimal128Array>()
    389
    0
                .with_precision_and_scale(10, 3)?;
    390
    391
    0
            generic_decimal_to_other_test_cast!(
    392
                decimal_array,
    393
    0
                Decimal128(10, 3),
    394
                Decimal128Array,
    395
    0
                Decimal128(20, 6),
    396
    0
                [
    397
    0
                    Some(1_234_000),
    398
    0
                    Some(2_222_000),
    399
    0
                    Some(3_000),
    400
    0
                    Some(4_000_000),
    401
    0
                    Some(5_000_000),
    402
    0
                    None
    403
    0
                ],
    404
    0
                None
    405
            );
    406
    407
    0
            let decimal_array = array
    408
    0
                .into_iter()
    409
    0
                .collect::<Decimal128Array>()
    410
    0
                .with_precision_and_scale(10, 3)?;
    411
    412
    0
            generic_decimal_to_other_test_cast!(
    413
                decimal_array,
    414
    0
                Decimal128(10, 3),
    415
                Decimal128Array,
    416
    0
                Decimal128(10, 2),
    417
    0
                [Some(123), Some(222), Some(0), Some(400), Some(500), None],
    418
    0
                None
    419
            );
    420
    421
    0
            Ok(())
    422
    0
        }
    423
    424
        #[test]
    425
    0
        fn test_cast_decimal_to_decimal_overflow() -> Result<()> {
    426
    0
            let array = vec![Some(123456789)];
    427
    428
    0
            let decimal_array = array
    429
    0
                .clone()
    430
    0
                .into_iter()
    431
    0
                .collect::<Decimal128Array>()
    432
    0
                .with_precision_and_scale(10, 3)?;
    433
    434
    0
            let schema = Schema::new(vec![Field::new("a", Decimal128(10, 3), false)]);
    435
    0
            let batch = RecordBatch::try_new(
    436
    0
                Arc::new(schema.clone()),
    437
    0
                vec![Arc::new(decimal_array)],
    438
    0
            )?;
    439
    0
            let expression =
    440
    0
                cast_with_options(col("a", &schema)?, &schema, Decimal128(6, 2), None)?;
    441
    0
            let e = expression.evaluate(&batch).unwrap_err().strip_backtrace(); // panics on OK
    442
    0
            assert_snapshot!(e, @"Arrow error: Invalid argument error: 123456.79 is too large to store in a Decimal128 of precision 6. Max is 9999.99");
    443
            // safe cast should return null
    444
    0
            let expression_safe = cast_with_options(
    445
    0
                col("a", &schema)?,
    446
    0
                &schema,
    447
    0
                Decimal128(6, 2),
    448
    0
                Some(DEFAULT_SAFE_CAST_OPTIONS),
    449
    0
            )?;
    450
    0
            let result_safe = expression_safe
    451
    0
                .evaluate(&batch)?
    452
    0
                .into_array(batch.num_rows())
    453
    0
                .expect("failed to convert to array");
    454
    455
    0
            assert!(result_safe.is_null(0));
    456
    457
    0
            Ok(())
    458
    0
        }
    459
    460
        #[test]
    461
    0
        fn test_cast_decimal_to_numeric() -> Result<()> {
    462
    0
            let array = vec![Some(1), Some(2), Some(3), Some(4), Some(5), None];
    463
            // decimal to i8
    464
    0
            let decimal_array = array
    465
    0
                .clone()
    466
    0
                .into_iter()
    467
    0
                .collect::<Decimal128Array>()
    468
    0
                .with_precision_and_scale(10, 0)?;
    469
    0
            generic_decimal_to_other_test_cast!(
    470
                decimal_array,
    471
    0
                Decimal128(10, 0),
    472
                Int8Array,
    473
    0
                Int8,
    474
    0
                [
    475
    0
                    Some(1_i8),
    476
    0
                    Some(2_i8),
    477
    0
                    Some(3_i8),
    478
    0
                    Some(4_i8),
    479
    0
                    Some(5_i8),
    480
    0
                    None
    481
    0
                ],
    482
    0
                None
    483
            );
    484
    485
            // decimal to i16
    486
    0
            let decimal_array = array
    487
    0
                .clone()
    488
    0
                .into_iter()
    489
    0
                .collect::<Decimal128Array>()
    490
    0
                .with_precision_and_scale(10, 0)?;
    491
    0
            generic_decimal_to_other_test_cast!(
    492
                decimal_array,
    493
    0
                Decimal128(10, 0),
    494
                Int16Array,
    495
    0
                Int16,
    496
    0
                [
    497
    0
                    Some(1_i16),
    498
    0
                    Some(2_i16),
    499
    0
                    Some(3_i16),
    500
    0
                    Some(4_i16),
    501
    0
                    Some(5_i16),
    502
    0
                    None
    503
    0
                ],
    504
    0
                None
    505
            );
    506
    507
            // decimal to i32
    508
    0
            let decimal_array = array
    509
    0
                .clone()
    510
    0
                .into_iter()
    511
    0
                .collect::<Decimal128Array>()
    512
    0
                .with_precision_and_scale(10, 0)?;
    513
    0
            generic_decimal_to_other_test_cast!(
    514
                decimal_array,
    515
    0
                Decimal128(10, 0),
    516
                Int32Array,
    517
    0
                Int32,
    518
    0
                [
    519
    0
                    Some(1_i32),
    520
    0
                    Some(2_i32),
    521
    0
                    Some(3_i32),
    522
    0
                    Some(4_i32),
    523
    0
                    Some(5_i32),
    524
    0
                    None
    525
    0
                ],
    526
    0
                None
    527
            );
    528
    529
            // decimal to i64
    530
    0
            let decimal_array = array
    531
    0
                .into_iter()
    532
    0
                .collect::<Decimal128Array>()
    533
    0
                .with_precision_and_scale(10, 0)?;
    534
    0
            generic_decimal_to_other_test_cast!(
    535
                decimal_array,
    536
    0
                Decimal128(10, 0),
    537
                Int64Array,
    538
    0
                Int64,
    539
    0
                [
    540
    0
                    Some(1_i64),
    541
    0
                    Some(2_i64),
    542
    0
                    Some(3_i64),
    543
    0
                    Some(4_i64),
    544
    0
                    Some(5_i64),
    545
    0
                    None
    546
    0
                ],
    547
    0
                None
    548
            );
    549
    550
            // decimal to float32
    551
    0
            let array = vec![
    552
    0
                Some(1234),
    553
    0
                Some(2222),
    554
    0
                Some(3),
    555
    0
                Some(4000),
    556
    0
                Some(5000),
    557
    0
                None,
    558
            ];
    559
    0
            let decimal_array = array
    560
    0
                .clone()
    561
    0
                .into_iter()
    562
    0
                .collect::<Decimal128Array>()
    563
    0
                .with_precision_and_scale(10, 3)?;
    564
    0
            generic_decimal_to_other_test_cast!(
    565
                decimal_array,
    566
    0
                Decimal128(10, 3),
    567
                Float32Array,
    568
    0
                Float32,
    569
    0
                [
    570
    0
                    Some(1.234_f32),
    571
    0
                    Some(2.222_f32),
    572
    0
                    Some(0.003_f32),
    573
    0
                    Some(4.0_f32),
    574
    0
                    Some(5.0_f32),
    575
    0
                    None
    576
    0
                ],
    577
    0
                None
    578
            );
    579
    580
            // decimal to float64
    581
    0
            let decimal_array = array
    582
    0
                .into_iter()
    583
    0
                .collect::<Decimal128Array>()
    584
    0
                .with_precision_and_scale(20, 6)?;
    585
    0
            generic_decimal_to_other_test_cast!(
    586
                decimal_array,
    587
    0
                Decimal128(20, 6),
    588
                Float64Array,
    589
    0
                Float64,
    590
    0
                [
    591
    0
                    Some(0.001234_f64),
    592
    0
                    Some(0.002222_f64),
    593
    0
                    Some(0.000003_f64),
    594
    0
                    Some(0.004_f64),
    595
    0
                    Some(0.005_f64),
    596
    0
                    None
    597
    0
                ],
    598
    0
                None
    599
            );
    600
    0
            Ok(())
    601
    0
        }
    602
    603
        #[test]
    604
    0
        fn test_cast_numeric_to_decimal() -> Result<()> {
    605
            // int8
    606
    0
            generic_test_cast!(
    607
                Int8Array,
    608
    0
                Int8,
    609
    0
                vec![1, 2, 3, 4, 5],
    610
                Decimal128Array,
    611
    0
                Decimal128(3, 0),
    612
    0
                [Some(1), Some(2), Some(3), Some(4), Some(5)],
    613
    0
                None
    614
            );
    615
    616
            // int16
    617
    0
            generic_test_cast!(
    618
                Int16Array,
    619
    0
                Int16,
    620
    0
                vec![1, 2, 3, 4, 5],
    621
                Decimal128Array,
    622
    0
                Decimal128(5, 0),
    623
    0
                [Some(1), Some(2), Some(3), Some(4), Some(5)],
    624
    0
                None
    625
            );
    626
    627
            // int32
    628
    0
            generic_test_cast!(
    629
                Int32Array,
    630
    0
                Int32,
    631
    0
                vec![1, 2, 3, 4, 5],
    632
                Decimal128Array,
    633
    0
                Decimal128(10, 0),
    634
    0
                [Some(1), Some(2), Some(3), Some(4), Some(5)],
    635
    0
                None
    636
            );
    637
    638
            // int64
    639
    0
            generic_test_cast!(
    640
                Int64Array,
    641
    0
                Int64,
    642
    0
                vec![1, 2, 3, 4, 5],
    643
                Decimal128Array,
    644
    0
                Decimal128(20, 0),
    645
    0
                [Some(1), Some(2), Some(3), Some(4), Some(5)],
    646
    0
                None
    647
            );
    648
    649
            // int64 to different scale
    650
    0
            generic_test_cast!(
    651
                Int64Array,
    652
    0
                Int64,
    653
    0
                vec![1, 2, 3, 4, 5],
    654
                Decimal128Array,
    655
    0
                Decimal128(20, 2),
    656
    0
                [Some(100), Some(200), Some(300), Some(400), Some(500)],
    657
    0
                None
    658
            );
    659
    660
            // float32
    661
    0
            generic_test_cast!(
    662
                Float32Array,
    663
    0
                Float32,
    664
    0
                vec![1.5, 2.5, 3.0, 1.123_456_8, 5.50],
    665
                Decimal128Array,
    666
    0
                Decimal128(10, 2),
    667
    0
                [Some(150), Some(250), Some(300), Some(112), Some(550)],
    668
    0
                None
    669
            );
    670
    671
            // float64
    672
    0
            generic_test_cast!(
    673
                Float64Array,
    674
    0
                Float64,
    675
    0
                vec![1.5, 2.5, 3.0, 1.123_456_8, 5.50],
    676
                Decimal128Array,
    677
    0
                Decimal128(20, 4),
    678
    0
                [
    679
    0
                    Some(15000),
    680
    0
                    Some(25000),
    681
    0
                    Some(30000),
    682
    0
                    Some(11235),
    683
    0
                    Some(55000)
    684
    0
                ],
    685
    0
                None
    686
            );
    687
    0
            Ok(())
    688
    0
        }
    689
    690
        #[test]
    691
    0
        fn test_cast_i32_u32() -> Result<()> {
    692
    0
            generic_test_cast!(
    693
                Int32Array,
    694
    0
                Int32,
    695
    0
                vec![1, 2, 3, 4, 5],
    696
                UInt32Array,
    697
    0
                UInt32,
    698
    0
                [
    699
    0
                    Some(1_u32),
    700
    0
                    Some(2_u32),
    701
    0
                    Some(3_u32),
    702
    0
                    Some(4_u32),
    703
    0
                    Some(5_u32)
    704
    0
                ],
    705
    0
                None
    706
            );
    707
    0
            Ok(())
    708
    0
        }
    709
    710
        #[test]
    711
    0
        fn test_cast_i32_utf8() -> Result<()> {
    712
    0
            generic_test_cast!(
    713
                Int32Array,
    714
    0
                Int32,
    715
    0
                vec![1, 2, 3, 4, 5],
    716
                StringArray,
    717
    0
                Utf8,
    718
    0
                [Some("1"), Some("2"), Some("3"), Some("4"), Some("5")],
    719
    0
                None
    720
            );
    721
    0
            Ok(())
    722
    0
        }
    723
    724
        #[test]
    725
    0
        fn test_cast_i64_t64() -> Result<()> {
    726
    0
            let original = vec![1, 2, 3, 4, 5];
    727
    0
            let expected: Vec<Option<i64>> = original
    728
    0
                .iter()
    729
    0
                .map(|i| Some(Time64NanosecondArray::from(vec![*i]).value(0)))
    730
    0
                .collect();
    731
    0
            generic_test_cast!(
    732
                Int64Array,
    733
    0
                Int64,
    734
    0
                original,
    735
                TimestampNanosecondArray,
    736
    0
                Timestamp(TimeUnit::Nanosecond, None),
    737
    0
                expected,
    738
    0
                None
    739
            );
    740
    0
            Ok(())
    741
    0
        }
    742
    743
        #[test]
    744
    0
        fn invalid_cast() {
    745
            // Ensure a useful error happens at plan time if invalid casts are used
    746
    0
            let schema = Schema::new(vec![Field::new("a", Int32, false)]);
    747
    748
    0
            let result = cast(
    749
    0
                col("a", &schema).unwrap(),
    750
    0
                &schema,
    751
    0
                Interval(IntervalUnit::MonthDayNano),
    752
            );
    753
    0
            result.expect_err("expected Invalid CAST");
    754
    0
        }
    755
    756
        #[test]
    757
    0
        fn invalid_cast_with_options_error() -> Result<()> {
    758
            // Ensure a useful error happens at plan time if invalid casts are used
    759
    0
            let schema = Schema::new(vec![Field::new("a", Utf8, false)]);
    760
    0
            let a = StringArray::from(vec!["9.1"]);
    761
    0
            let batch = RecordBatch::try_new(Arc::new(schema.clone()), vec![Arc::new(a)])?;
    762
    0
            let expression = cast_with_options(col("a", &schema)?, &schema, Int32, None)?;
    763
    0
            let result = expression.evaluate(&batch);
    764
    765
    0
            match result {
    766
    0
                Ok(_) => panic!("expected error"),
    767
    0
                Err(e) => {
    768
    0
                    assert!(e
    769
    0
                        .to_string()
    770
    0
                        .contains("Cannot cast string '9.1' to value of Int32 type"))
    771
                }
    772
            }
    773
    0
            Ok(())
    774
    0
        }
    775
    776
        #[test]
    777
        #[ignore] // TODO: https://github.com/apache/datafusion/issues/5396
    778
    0
        fn test_cast_decimal() -> Result<()> {
    779
    0
            let schema = Schema::new(vec![Field::new("a", Int64, false)]);
    780
    0
            let a = Int64Array::from(vec![100]);
    781
    0
            let batch = RecordBatch::try_new(Arc::new(schema.clone()), vec![Arc::new(a)])?;
    782
    0
            let expression =
    783
    0
                cast_with_options(col("a", &schema)?, &schema, Decimal128(38, 38), None)?;
    784
    0
            expression.evaluate(&batch)?;
    785
    0
            Ok(())
    786
    0
        }
    787
    788
        #[test]
    789
    0
        fn test_fmt_sql() -> Result<()> {
    790
    0
            let schema = Schema::new(vec![Field::new("a", Int32, true)]);
    791
    792
            // Test numeric casting
    793
    0
            let expr = cast(col("a", &schema)?, &schema, Int64)?;
    794
    0
            let display_string = expr.to_string();
    795
    0
            assert_eq!(display_string, "CAST(a@0 AS Int64)");
    796
    0
            let sql_string = fmt_sql(expr.as_ref()).to_string();
    797
    0
            assert_eq!(sql_string, "CAST(a AS Int64)");
    798
    799
            // Test string casting
    800
    0
            let schema = Schema::new(vec![Field::new("b", Utf8, true)]);
    801
    0
            let expr = cast(col("b", &schema)?, &schema, Int32)?;
    802
    0
            let display_string = expr.to_string();
    803
    0
            assert_eq!(display_string, "CAST(b@0 AS Int32)");
    804
    0
            let sql_string = fmt_sql(expr.as_ref()).to_string();
    805
    0
            assert_eq!(sql_string, "CAST(b AS Int32)");
    806
    807
    0
            Ok(())
    808
    0
        }
    809
    }