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