## 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/functions/src/core/nvl.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 crate::core::coalesce::CoalesceFunc;
    19
    use arrow::datatypes::{DataType, FieldRef};
    20
    use datafusion_common::Result;
    21
    use datafusion_expr::simplify::{ExprSimplifyResult, SimplifyInfo};
    22
    use datafusion_expr::{
    23
        ColumnarValue, Documentation, Expr, ReturnFieldArgs, ScalarFunctionArgs,
    24
        ScalarUDFImpl, Signature, Volatility,
    25
    };
    26
    use datafusion_macros::user_doc;
    27
    28
    #[user_doc(
    29
        doc_section(label = "Conditional Functions"),
    30
        description = "Returns _expression2_ if _expression1_ is NULL otherwise it returns _expression1_ and _expression2_ is not evaluated. This function can be used to substitute a default value for NULL values.",
    31
        syntax_example = "nvl(expression1, expression2)",
    32
        sql_example = r#"```sql
    33
    > select nvl(null, 'a');
    34
    +---------------------+
    35
    | nvl(NULL,Utf8("a")) |
    36
    +---------------------+
    37
    | a                   |
    38
    +---------------------+\
    39
    > select nvl('b', 'a');
    40
    +--------------------------+
    41
    | nvl(Utf8("b"),Utf8("a")) |
    42
    +--------------------------+
    43
    | b                        |
    44
    +--------------------------+
    45
    ```
    46
    "#,
    47
        argument(
    48
            name = "expression1",
    49
            description = "Expression to return if not null. Can be a constant, column, or function, and any combination of operators."
    50
        ),
    51
        argument(
    52
            name = "expression2",
    53
            description = "Expression to return if expr1 is null. Can be a constant, column, or function, and any combination of operators."
    54
        )
    55
    )]
    56
    #[derive(Debug, PartialEq, Eq, Hash)]
    57
    pub struct NVLFunc {
    58
        coalesce: CoalesceFunc,
    59
        aliases: Vec<String>,
    60
    }
    61
    62
    /// Currently supported types by the nvl/ifnull function.
    63
    /// The order of these types correspond to the order on which coercion applies
    64
    /// This should thus be from least informative to most informative
    65
    static SUPPORTED_NVL_TYPES: &[DataType] = &[
    66
        DataType::Boolean,
    67
        DataType::UInt8,
    68
        DataType::UInt16,
    69
        DataType::UInt32,
    70
        DataType::UInt64,
    71
        DataType::Int8,
    72
        DataType::Int16,
    73
        DataType::Int32,
    74
        DataType::Int64,
    75
        DataType::Float32,
    76
        DataType::Float64,
    77
        DataType::Utf8View,
    78
        DataType::Utf8,
    79
        DataType::LargeUtf8,
    80
    ];
    81
    82
    impl Default for NVLFunc {
    83
    0
        fn default() -> Self {
    84
    0
            Self::new()
    85
    0
        }
    86
    }
    87
    88
    impl NVLFunc {
    89
    0
        pub fn new() -> Self {
    90
    0
            Self {
    91
    0
                coalesce: CoalesceFunc {
    92
    0
                    signature: Signature::uniform(
    93
    0
                        2,
    94
    0
                        SUPPORTED_NVL_TYPES.to_vec(),
    95
    0
                        Volatility::Immutable,
    96
    0
                    ),
    97
    0
                },
    98
    0
                aliases: vec![String::from("ifnull")],
    99
    0
            }
    100
    0
        }
    101
    }
    102
    103
    impl ScalarUDFImpl for NVLFunc {
    104
    0
        fn as_any(&self) -> &dyn std::any::Any {
    105
    0
            self
    106
    0
        }
    107
    108
    0
        fn name(&self) -> &str {
    109
    0
            "nvl"
    110
    0
        }
    111
    112
    0
        fn signature(&self) -> &Signature {
    113
    0
            &self.coalesce.signature
    114
    0
        }
    115
    116
    0
        fn return_type(&self, arg_types: &[DataType]) -> Result<DataType> {
    117
    0
            self.coalesce.return_type(arg_types)
    118
    0
        }
    119
    120
    0
        fn return_field_from_args(&self, args: ReturnFieldArgs) -> Result<FieldRef> {
    121
    0
            self.coalesce.return_field_from_args(args)
    122
    0
        }
    123
    124
    0
        fn simplify(
    125
    0
            &self,
    126
    0
            args: Vec<Expr>,
    127
    0
            info: &dyn SimplifyInfo,
    128
    0
        ) -> Result<ExprSimplifyResult> {
    129
    0
            self.coalesce.simplify(args, info)
    130
    0
        }
    131
    132
    0
        fn invoke_with_args(&self, args: ScalarFunctionArgs) -> Result<ColumnarValue> {
    133
    0
            self.coalesce.invoke_with_args(args)
    134
    0
        }
    135
    136
    0
        fn conditional_arguments<'a>(
    137
    0
            &self,
    138
    0
            args: &'a [Expr],
    139
    0
        ) -> Option<(Vec<&'a Expr>, Vec<&'a Expr>)> {
    140
    0
            self.coalesce.conditional_arguments(args)
    141
    0
        }
    142
    143
    0
        fn short_circuits(&self) -> bool {
    144
    0
            self.coalesce.short_circuits()
    145
    0
        }
    146
    147
    0
        fn aliases(&self) -> &[String] {
    148
    0
            &self.aliases
    149
    0
        }
    150
    151
    0
        fn documentation(&self) -> Option<&Documentation> {
    152
    0
            self.doc()
    153
    0
        }
    154
    }