## 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/string/upper.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::string::common::to_upper;
    19
    use crate::utils::utf8_to_str_type;
    20
    use arrow::datatypes::DataType;
    21
    use datafusion_common::types::logical_string;
    22
    use datafusion_common::Result;
    23
    use datafusion_expr::{
    24
        Coercion, ColumnarValue, Documentation, ScalarFunctionArgs, ScalarUDFImpl, Signature,
    25
        TypeSignatureClass, Volatility,
    26
    };
    27
    use datafusion_macros::user_doc;
    28
    use std::any::Any;
    29
    30
    #[user_doc(
    31
        doc_section(label = "String Functions"),
    32
        description = "Converts a string to upper-case.",
    33
        syntax_example = "upper(str)",
    34
        sql_example = r#"```sql
    35
    > select upper('dataFusion');
    36
    +---------------------------+
    37
    | upper(Utf8("dataFusion")) |
    38
    +---------------------------+
    39
    | DATAFUSION                |
    40
    +---------------------------+
    41
    ```"#,
    42
        standard_argument(name = "str", prefix = "String"),
    43
        related_udf(name = "initcap"),
    44
        related_udf(name = "lower")
    45
    )]
    46
    #[derive(Debug, PartialEq, Eq, Hash)]
    47
    pub struct UpperFunc {
    48
        signature: Signature,
    49
    }
    50
    51
    impl Default for UpperFunc {
    52
    0
        fn default() -> Self {
    53
    0
            Self::new()
    54
    0
        }
    55
    }
    56
    57
    impl UpperFunc {
    58
    0
        pub fn new() -> Self {
    59
    0
            Self {
    60
    0
                signature: Signature::coercible(
    61
    0
                    vec![Coercion::new_exact(TypeSignatureClass::Native(
    62
    0
                        logical_string(),
    63
    0
                    ))],
    64
    0
                    Volatility::Immutable,
    65
    0
                ),
    66
    0
            }
    67
    0
        }
    68
    }
    69
    70
    impl ScalarUDFImpl for UpperFunc {
    71
    0
        fn as_any(&self) -> &dyn Any {
    72
    0
            self
    73
    0
        }
    74
    75
    0
        fn name(&self) -> &str {
    76
    0
            "upper"
    77
    0
        }
    78
    79
    0
        fn signature(&self) -> &Signature {
    80
    0
            &self.signature
    81
    0
        }
    82
    83
    0
        fn return_type(&self, arg_types: &[DataType]) -> Result<DataType> {
    84
    0
            utf8_to_str_type(&arg_types[0], "upper")
    85
    0
        }
    86
    87
    0
        fn invoke_with_args(&self, args: ScalarFunctionArgs) -> Result<ColumnarValue> {
    88
    0
            to_upper(&args.args, "upper")
    89
    0
        }
    90
    91
    0
        fn documentation(&self) -> Option<&Documentation> {
    92
    0
            self.doc()
    93
    0
        }
    94
    }
    95
    96
    #[cfg(test)]
    97
    mod tests {
    98
        use super::*;
    99
        use arrow::array::{Array, ArrayRef, StringArray};
    100
        use arrow::datatypes::DataType::Utf8;
    101
        use arrow::datatypes::Field;
    102
        use datafusion_common::config::ConfigOptions;
    103
        use std::sync::Arc;
    104
    105
        fn to_upper(input: ArrayRef, expected: ArrayRef) -> Result<()> {
    106
            let func = UpperFunc::new();
    107
    108
            let arg_field = Field::new("a", input.data_type().clone(), true).into();
    109
            let args = ScalarFunctionArgs {
    110
                number_rows: input.len(),
    111
                args: vec![ColumnarValue::Array(input)],
    112
                arg_fields: vec![arg_field],
    113
                return_field: Field::new("f", Utf8, true).into(),
    114
                config_options: Arc::new(ConfigOptions::default()),
    115
            };
    116
    117
            let result = match func.invoke_with_args(args)? {
    118
                ColumnarValue::Array(result) => result,
    119
                _ => unreachable!("upper"),
    120
            };
    121
            assert_eq!(&expected, &result);
    122
            Ok(())
    123
        }
    124
    125
        #[test]
    126
        fn upper_maybe_optimization() -> Result<()> {
    127
            let input = Arc::new(StringArray::from(vec![
    128
                Some("农历新年"),
    129
                None,
    130
                Some("datafusion"),
    131
                Some("0123456789"),
    132
                Some(""),
    133
            ])) as ArrayRef;
    134
    135
            let expected = Arc::new(StringArray::from(vec![
    136
                Some("农历新年"),
    137
                None,
    138
                Some("DATAFUSION"),
    139
                Some("0123456789"),
    140
                Some(""),
    141
            ])) as ArrayRef;
    142
    143
            to_upper(input, expected)
    144
        }
    145
    146
        #[test]
    147
        fn upper_full_optimization() -> Result<()> {
    148
            let input = Arc::new(StringArray::from(vec![
    149
                Some("arrow"),
    150
                None,
    151
                Some("datafusion"),
    152
                Some("0123456789"),
    153
                Some(""),
    154
            ])) as ArrayRef;
    155
    156
            let expected = Arc::new(StringArray::from(vec![
    157
                Some("ARROW"),
    158
                None,
    159
                Some("DATAFUSION"),
    160
                Some("0123456789"),
    161
                Some(""),
    162
            ])) as ArrayRef;
    163
    164
            to_upper(input, expected)
    165
        }
    166
    167
        #[test]
    168
        fn upper_partial_optimization() -> Result<()> {
    169
            let input = Arc::new(StringArray::from(vec![
    170
                Some("arrow"),
    171
                None,
    172
                Some("datafusion"),
    173
                Some("@_"),
    174
                Some("0123456789"),
    175
                Some(""),
    176
                Some("\t\n"),
    177
                Some("ὀδυσσεύς"),
    178
                Some("tschüß"),
    179
                Some("ⱦ"), // Ⱦ: length change
    180
                Some("农历新年"),
    181
            ])) as ArrayRef;
    182
    183
            let expected = Arc::new(StringArray::from(vec![
    184
                Some("ARROW"),
    185
                None,
    186
                Some("DATAFUSION"),
    187
                Some("@_"),
    188
                Some("0123456789"),
    189
                Some(""),
    190
                Some("\t\n"),
    191
                Some("ὈΔΥΣΣΕΎΣ"),
    192
                Some("TSCHÜSS"),
    193
                Some("Ⱦ"),
    194
                Some("农历新年"),
    195
            ])) as ArrayRef;
    196
    197
            to_upper(input, expected)
    198
        }
    199
    }