## Coverage Report

#### Created: 2024-10-13 08:39

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

    Line
    Count
    Source (jump to first uncovered line)
    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
    //! Literal expressions for physical operations
    19
    20
    use std::any::Any;
    21
    use std::hash::{Hash, Hasher};
    22
    use std::sync::Arc;
    23
    24
    use crate::physical_expr::{down_cast_any_ref, PhysicalExpr};
    25
    26
    use arrow::{
    27
        datatypes::{DataType, Schema},
    28
        record_batch::RecordBatch,
    29
    };
    30
    use datafusion_common::{Result, ScalarValue};
    31
    use datafusion_expr::Expr;
    32
    use datafusion_expr_common::columnar_value::ColumnarValue;
    33
    use datafusion_expr_common::interval_arithmetic::Interval;
    34
    use datafusion_expr_common::sort_properties::{ExprProperties, SortProperties};
    35
    36
    /// Represents a literal value
    37
    #[derive(Debug, PartialEq, Eq, Hash)]
    38
    pub struct Literal {
    39
        value: ScalarValue,
    40
    }
    41
    42
    impl Literal {
    43
        /// Create a literal value expression
    44
    1.53k
        pub fn new(value: ScalarValue) -> Self {
    45
    1.53k
            Self { value }
    46
    1.53k
        }
    47
    48
        /// Get the scalar value
    49
    4.21k
        pub fn value(&self) -> &ScalarValue {
    50
    4.21k
            &self.value
    51
    4.21k
        }
    52
    }
    53
    54
    impl std::fmt::Display for Literal {
    55
    0
        fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
    56
    0
            write!(f, "{}", self.value)
    57
    0
        }
    58
    }
    59
    60
    impl PhysicalExpr for Literal {
    61
        /// Return a reference to Any that can be used for downcasting
    62
    35.9k
        fn as_any(&self) -> &dyn Any {
    63
    35.9k
            self
    64
    35.9k
        }
    65
    66
    100k
        fn data_type(&self, _input_schema: &Schema) -> Result<DataType> {
    67
    100k
            Ok(self.value.data_type())
    68
    100k
        }
    69
    70
    0
        fn nullable(&self, _input_schema: &Schema) -> Result<bool> {
    71
    0
            Ok(self.value.is_null())
    72
    0
        }
    73
    74
    88.4k
        fn evaluate(&self, _batch: &RecordBatch) -> Result<ColumnarValue> {
    75
    88.4k
            Ok(ColumnarValue::Scalar(self.value.clone()))
    76
    88.4k
        }
    77
    78
    5.49k
        fn children(&self) -> Vec<&Arc<dyn PhysicalExpr>> {
    79
    5.49k
            vec![]
    80
    5.49k
        }
    81
    82
    0
        fn with_new_children(
    83
    0
            self: Arc<Self>,
    84
    0
            _children: Vec<Arc<dyn PhysicalExpr>>,
    85
    0
        ) -> Result<Arc<dyn PhysicalExpr>> {
    86
    0
            Ok(self)
    87
    0
        }
    88
    89
    0
        fn dyn_hash(&self, state: &mut dyn Hasher) {
    90
    0
            let mut s = state;
    91
    0
            self.hash(&mut s);
    92
    0
        }
    93
    94
    1
        fn get_properties(&self, _children: &[ExprProperties]) -> Result<ExprProperties> {
    95
    1
            Ok(ExprProperties {
    96
    1
                sort_properties: SortProperties::Singleton,
    97
    1
                range: Interval::try_new(self.value().clone(), self.value().clone())?0,
    98
            })
    99
    1
        }
    100
    }
    101
    102
    impl PartialEq<dyn Any> for Literal {
    103
    33.8k
        fn eq(&self, other: &dyn Any) -> bool {
    104
    33.8k
            down_cast_any_ref(other)
    105
    33.8k
                .downcast_ref::<Self>()
    106
    33.8k
                .map(|x| self == x8.43k)
    107
    33.8k
                .unwrap_or(false)
    108
    33.8k
        }
    109
    }
    110
    111
    /// Create a literal expression
    112
    87
    pub fn lit<T: datafusion_expr::Literal>(value: T) -> Arc<dyn PhysicalExpr> {
    113
    87
        match value.lit() {
    114
    87
            Expr::Literal(v) => Arc::new(Literal::new(v)),
    115
    0
            _ => unreachable!(),
    116
        }
    117
    87
    }
    118
    119
    #[cfg(test)]
    120
    mod tests {
    121
        use super::*;
    122
    123
        use arrow::array::Int32Array;
    124
        use arrow::datatypes::*;
    125
        use datafusion_common::cast::as_int32_array;
    126
    127
        #[test]
    128
        fn literal_i32() -> Result<()> {
    129
            // create an arbitrary record bacth
    130
            let schema = Schema::new(vec![Field::new("a", DataType::Int32, true)]);
    131
            let a = Int32Array::from(vec![Some(1), None, Some(3), Some(4), Some(5)]);
    132
            let batch = RecordBatch::try_new(Arc::new(schema), vec![Arc::new(a)])?;
    133
    134
            // create and evaluate a literal expression
    135
            let literal_expr = lit(42i32);
    136
            assert_eq!("42", format!("{literal_expr}"));
    137
    138
            let literal_array = literal_expr
    139
                .evaluate(&batch)?
    140
                .into_array(batch.num_rows())
    141
                .expect("Failed to convert to array");
    142
            let literal_array = as_int32_array(&literal_array)?;
    143
    144
            // note that the contents of the literal array are unrelated to the batch contents except for the length of the array
    145
            assert_eq!(literal_array.len(), 5); // 5 rows in the batch
    146
            for i in 0..literal_array.len() {
    147
                assert_eq!(literal_array.value(i), 42);
    148
            }
    149
    150
            Ok(())
    151
        }
    152
    }