## 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/common/src/param_value.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::error::{_plan_datafusion_err, _plan_err};
    19
    use crate::metadata::{check_metadata_with_storage_equal, ScalarAndMetadata};
    20
    use crate::{Result, ScalarValue};
    21
    use arrow::datatypes::{DataType, Field, FieldRef};
    22
    use std::collections::HashMap;
    23
    24
    /// The parameter value corresponding to the placeholder
    25
    #[derive(Debug, Clone)]
    26
    pub enum ParamValues {
    27
        /// For positional query parameters, like `SELECT * FROM test WHERE a > $1 AND b = $2`
    28
        List(Vec<ScalarAndMetadata>),
    29
        /// For named query parameters, like `SELECT * FROM test WHERE a > $foo AND b = $goo`
    30
        Map(HashMap<String, ScalarAndMetadata>),
    31
    }
    32
    33
    impl ParamValues {
    34
        /// Verify parameter list length and DataType
    35
        ///
    36
        /// Use [`ParamValues::verify_fields`] to ensure field metadata is considered when
    37
        /// computing type equality.
    38
        #[deprecated(since = "51.0.0", note = "Use verify_fields instead")]
    39
    0
        pub fn verify(&self, expect: &[DataType]) -> Result<()> {
    40
            // make dummy Fields
    41
    0
            let expect = expect
    42
    0
                .iter()
    43
    0
                .map(|dt| Field::new("", dt.clone(), true).into())
    44
    0
                .collect::<Vec<_>>();
    45
    0
            self.verify_fields(&expect)
    46
    0
        }
    47
    48
        /// Verify parameter list length and type
    49
    0
        pub fn verify_fields(&self, expect: &[FieldRef]) -> Result<()> {
    50
    0
            match self {
    51
    0
                ParamValues::List(list) => {
    52
                    // Verify if the number of params matches the number of values
    53
    0
                    if expect.len() != list.len() {
    54
    0
                        return _plan_err!(
    55
    0
                            "Expected {} parameters, got {}",
    56
    0
                            expect.len(),
    57
    0
                            list.len()
    58
                        );
    59
    0
                    }
    60
    61
                    // Verify if the types of the params matches the types of the values
    62
    0
                    let iter = expect.iter().zip(list.iter());
    63
    0
                    for (i, (param_type, lit)) in iter.enumerate() {
    64
    0
                        check_metadata_with_storage_equal(
    65
                            (
    66
    0
                                &lit.value.data_type(),
    67
    0
                                lit.metadata.as_ref().map(|m| m.to_hashmap()).as_ref(),
    68
                            ),
    69
    0
                            (param_type.data_type(), Some(param_type.metadata())),
    70
    0
                            "parameter",
    71
    0
                            &format!(" at index {i}"),
    72
    0
                        )?;
    73
                    }
    74
    0
                    Ok(())
    75
                }
    76
                ParamValues::Map(_) => {
    77
                    // If it is a named query, variables can be reused,
    78
                    // but the lengths are not necessarily equal
    79
    0
                    Ok(())
    80
                }
    81
            }
    82
    0
        }
    83
    84
    0
        pub fn get_placeholders_with_values(&self, id: &str) -> Result<ScalarAndMetadata> {
    85
    0
            match self {
    86
    0
                ParamValues::List(list) => {
    87
    0
                    if id.is_empty() {
    88
    0
                        return _plan_err!("Empty placeholder id");
    89
    0
                    }
    90
                    // convert id (in format $1, $2, ..) to idx (0, 1, ..)
    91
    0
                    let idx = id[1..]
    92
    0
                        .parse::<usize>()
    93
    0
                        .map_err(|e| {
    94
    0
                            _plan_datafusion_err!("Failed to parse placeholder id: {e}")
    95
    0
                        })?
    96
    0
                        .checked_sub(1);
    97
                    // value at the idx-th position in param_values should be the value for the placeholder
    98
    0
                    let value = idx.and_then(|idx| list.get(idx)).ok_or_else(|| {
    99
    0
                        _plan_datafusion_err!("No value found for placeholder with id {id}")
    100
    0
                    })?;
    101
    0
                    Ok(value.clone())
    102
                }
    103
    0
                ParamValues::Map(map) => {
    104
                    // convert name (in format $a, $b, ..) to mapped values (a, b, ..)
    105
    0
                    let name = &id[1..];
    106
                    // value at the name position in param_values should be the value for the placeholder
    107
    0
                    let value = map.get(name).ok_or_else(|| {
    108
    0
                        _plan_datafusion_err!("No value found for placeholder with name {id}")
    109
    0
                    })?;
    110
    0
                    Ok(value.clone())
    111
                }
    112
            }
    113
    0
        }
    114
    }
    115
    116
    impl From<Vec<ScalarValue>> for ParamValues {
    117
    0
        fn from(value: Vec<ScalarValue>) -> Self {
    118
    0
            Self::List(value.into_iter().map(ScalarAndMetadata::from).collect())
    119
    0
        }
    120
    }
    121
    122
    impl<K> From<Vec<(K, ScalarValue)>> for ParamValues
    123
    where
    124
        K: Into<String>,
    125
    {
    126
    0
        fn from(value: Vec<(K, ScalarValue)>) -> Self {
    127
    0
            let value: HashMap<String, ScalarAndMetadata> = value
    128
    0
                .into_iter()
    129
    0
                .map(|(k, v)| (k.into(), ScalarAndMetadata::from(v)))
    130
    0
                .collect();
    131
    0
            Self::Map(value)
    132
    0
        }
    133
    }
    134
    135
    impl<K> From<HashMap<K, ScalarValue>> for ParamValues
    136
    where
    137
        K: Into<String>,
    138
    {
    139
    0
        fn from(value: HashMap<K, ScalarValue>) -> Self {
    140
    0
            let value: HashMap<String, ScalarAndMetadata> = value
    141
    0
                .into_iter()
    142
    0
                .map(|(k, v)| (k.into(), ScalarAndMetadata::from(v)))
    143
    0
                .collect();
    144
    0
            Self::Map(value)
    145
    0
        }
    146
    }