datafusion_spark/function/map/
map_from_entries.rs1use std::sync::Arc;
19
20use crate::function::map::utils::{
21 get_list_offsets, get_list_values, map_from_keys_values_offsets_nulls,
22 map_type_from_key_value_types,
23};
24use arrow::array::{Array, ArrayRef, NullBufferBuilder, StructArray};
25use arrow::buffer::NullBuffer;
26use arrow::datatypes::{DataType, Field, FieldRef};
27use datafusion_common::config::MapKeyDedupPolicy;
28use datafusion_common::utils::take_function_args;
29use datafusion_common::{Result, exec_err, internal_err};
30use datafusion_expr::{
31 ColumnarValue, ReturnFieldArgs, ScalarFunctionArgs, ScalarUDFImpl, Signature,
32 Volatility,
33};
34use datafusion_functions::utils::make_scalar_function;
35
36#[derive(Debug, PartialEq, Eq, Hash)]
39pub struct MapFromEntries {
40 signature: Signature,
41}
42
43impl Default for MapFromEntries {
44 fn default() -> Self {
45 Self::new()
46 }
47}
48
49impl MapFromEntries {
50 pub fn new() -> Self {
51 Self {
52 signature: Signature::array(Volatility::Immutable),
53 }
54 }
55}
56
57impl ScalarUDFImpl for MapFromEntries {
58 fn name(&self) -> &str {
59 "map_from_entries"
60 }
61
62 fn signature(&self) -> &Signature {
63 &self.signature
64 }
65
66 fn return_type(&self, _arg_types: &[DataType]) -> Result<DataType> {
67 internal_err!("return_field_from_args should be used instead")
68 }
69
70 fn return_field_from_args(&self, args: ReturnFieldArgs) -> Result<FieldRef> {
71 let [entries_field] = args.arg_fields else {
72 return exec_err!("map_from_entries: expected one argument");
73 };
74
75 let (entries_element_field, entries_element_type) =
76 match entries_field.data_type() {
77 DataType::List(field)
78 | DataType::LargeList(field)
79 | DataType::FixedSizeList(field, _) => {
80 Ok((field.as_ref(), field.data_type()))
81 }
82 wrong_type => exec_err!(
83 "map_from_entries: expected array<struct<key, value>>, got {:?}",
84 wrong_type
85 ),
86 }?;
87
88 let (keys_type, values_type) = match entries_element_type {
89 DataType::Struct(fields) if fields.len() == 2 => {
90 Ok((fields[0].data_type(), fields[1].data_type()))
91 }
92 wrong_type => exec_err!(
93 "map_from_entries: expected array<struct<key, value>>, got {:?}",
94 wrong_type
95 ),
96 }?;
97
98 let map_type = map_type_from_key_value_types(keys_type, values_type);
99 let nullable = entries_field.is_nullable() || entries_element_field.is_nullable();
100
101 Ok(Arc::new(Field::new(self.name(), map_type, nullable)))
102 }
103
104 fn invoke_with_args(&self, args: ScalarFunctionArgs) -> Result<ColumnarValue> {
105 let last_value_wins =
106 args.config_options.spark.map_key_dedup_policy == MapKeyDedupPolicy::LastWin;
107 make_scalar_function(
108 move |args: &[ArrayRef]| map_from_entries_inner(args, last_value_wins),
109 vec![],
110 )(&args.args)
111 }
112}
113
114fn map_from_entries_inner(args: &[ArrayRef], last_value_wins: bool) -> Result<ArrayRef> {
115 let [entries] = take_function_args("map_from_entries", args)?;
116 let entries_offsets = get_list_offsets(entries)?;
117 let entries_values = get_list_values(entries)?;
118
119 let (flat_keys, flat_values) =
120 match entries_values.as_any().downcast_ref::<StructArray>() {
121 Some(a) => Ok((a.column(0), a.column(1))),
122 None => exec_err!(
123 "map_from_entries: expected array<struct<key, value>>, got {:?}",
124 entries_values.data_type()
125 ),
126 }?;
127
128 let entries_with_nulls = entries_values.nulls().and_then(|entries_inner_nulls| {
129 let mut builder = NullBufferBuilder::new_with_len(0);
130 let mut cur_offset = entries_offsets
131 .first()
132 .map(|offset| *offset as usize)
133 .unwrap_or(0);
134
135 for next_offset in entries_offsets.iter().skip(1) {
136 let num_entries = *next_offset as usize - cur_offset;
137 builder.append(
138 entries_inner_nulls
139 .slice(cur_offset, num_entries)
140 .null_count()
141 == 0,
142 );
143 cur_offset = *next_offset as usize;
144 }
145 builder.finish()
146 });
147
148 let res_nulls = NullBuffer::union(entries.nulls(), entries_with_nulls.as_ref());
149
150 map_from_keys_values_offsets_nulls(
151 flat_keys,
152 flat_values,
153 &entries_offsets,
154 &entries_offsets,
155 None,
156 res_nulls.as_ref(),
157 last_value_wins,
158 )
159}
160
161#[cfg(test)]
162mod tests {
163 use super::*;
164 use arrow::datatypes::Fields;
165
166 fn make_entries_field(array_nullable: bool, element_nullable: bool) -> FieldRef {
167 let struct_type = DataType::Struct(Fields::from(vec![
168 Field::new("key", DataType::Int32, false),
169 Field::new("value", DataType::Utf8, true),
170 ]));
171 Arc::new(Field::new(
172 "entries",
173 DataType::List(Arc::new(Field::new("item", struct_type, element_nullable))),
174 array_nullable,
175 ))
176 }
177
178 #[test]
179 fn test_map_from_entries_nullability_matches_input() {
180 let func = MapFromEntries::new();
181 let expected_type =
182 map_type_from_key_value_types(&DataType::Int32, &DataType::Utf8);
183
184 let non_nullable_field = make_entries_field(false, false);
186 let result = func
187 .return_field_from_args(ReturnFieldArgs {
188 arg_fields: &[Arc::clone(&non_nullable_field)],
189 scalar_arguments: &[None],
190 })
191 .expect("should infer field");
192 assert!(!result.is_nullable());
193 assert_eq!(result.data_type(), &expected_type);
194
195 let element_nullable_field = make_entries_field(false, true);
197 let result = func
198 .return_field_from_args(ReturnFieldArgs {
199 arg_fields: &[Arc::clone(&element_nullable_field)],
200 scalar_arguments: &[None],
201 })
202 .expect("should infer field");
203 assert!(result.is_nullable());
204 assert_eq!(result.data_type(), &expected_type);
205
206 let array_nullable_field = make_entries_field(true, false);
208 let result = func
209 .return_field_from_args(ReturnFieldArgs {
210 arg_fields: &[Arc::clone(&array_nullable_field)],
211 scalar_arguments: &[None],
212 })
213 .expect("should infer field");
214 assert!(result.is_nullable());
215 assert_eq!(result.data_type(), &expected_type);
216 }
217}