1use std::collections::VecDeque;
19use std::hash::Hash;
20use std::sync::Arc;
21
22use arrow::array::{
23 Array, ArrayData, ArrayRef, ArrowPrimitiveType, MapArray, OffsetSizeTrait,
24 StructArray, cast::AsArray,
25};
26use arrow::buffer::Buffer;
27use arrow::datatypes::{
28 DataType, Date32Type, Date64Type, Field, Int8Type, Int16Type, Int32Type, Int64Type,
29 SchemaBuilder, ToByteSlice, UInt8Type, UInt16Type, UInt32Type, UInt64Type,
30};
31
32use datafusion_common::utils::{fixed_size_list_to_arrays, list_to_arrays};
33use datafusion_common::{
34 HashSet, Result, ScalarValue, exec_err, utils::take_function_args,
35};
36use datafusion_expr::expr::ScalarFunction;
37use datafusion_expr::{
38 ColumnarValue, Documentation, Expr, ScalarFunctionArgs, ScalarUDFImpl, Signature,
39 Volatility,
40};
41use datafusion_macros::user_doc;
42
43use crate::make_array::make_array;
44
45pub fn map(keys: Vec<Expr>, values: Vec<Expr>) -> Expr {
47 let keys = make_array(keys);
48 let values = make_array(values);
49 Expr::ScalarFunction(ScalarFunction::new_udf(map_udf(), vec![keys, values]))
50}
51
52create_func!(MapFunc, map_udf);
53
54fn can_evaluate_to_const(args: &[ColumnarValue]) -> bool {
62 args.iter()
63 .all(|arg| matches!(arg, ColumnarValue::Scalar(_)))
64}
65
66fn into_array_and_type(
67 arg: ColumnarValue,
68 rows: usize,
69 expand_scalar: bool,
70) -> Result<(ArrayRef, DataType)> {
71 let data_type = arg.data_type();
72 let array = if expand_scalar {
73 arg.into_array(rows)?
74 } else {
75 get_first_array_ref(&arg)?
76 };
77
78 Ok((array, data_type))
79}
80
81fn make_map_batch(args: Vec<ColumnarValue>, number_rows: usize) -> Result<ColumnarValue> {
82 let can_evaluate_to_const = can_evaluate_to_const(&args);
83 let [keys_arg, values_arg] = take_function_args("make_map", args)?;
84 let expand_scalar = !can_evaluate_to_const;
85
86 let (keys, keys_data_type) =
87 into_array_and_type(keys_arg, number_rows, expand_scalar)?;
88 let (values, _) = into_array_and_type(values_arg, number_rows, expand_scalar)?;
89
90 validate_map_keys_for_data_type(&keys, &keys_data_type, can_evaluate_to_const)?;
91
92 make_map_batch_internal(&keys, &values, can_evaluate_to_const, &keys_data_type)
93}
94
95fn validate_unique_primitive_keys<T: ArrowPrimitiveType>(array: &dyn Array) -> Result<()>
96where
97 T::Native: Copy + Eq + Hash + std::fmt::Display,
98{
99 let primitive_array = array.as_primitive::<T>();
100 if primitive_array.null_count() > 0 {
101 return exec_err!("map key cannot be null");
102 }
103
104 if let Some(value) = find_duplicate_value(
105 primitive_array.len(),
106 primitive_array.values().iter().copied(),
107 ) {
108 return exec_err!("map key must be unique, duplicate key found: {}", value);
109 }
110
111 Ok(())
112}
113
114fn validate_unique_str_keys<'a>(
115 null_count: usize,
116 len: usize,
117 values: impl IntoIterator<Item = &'a str>,
118) -> Result<()> {
119 if null_count > 0 {
120 return exec_err!("map key cannot be null");
121 }
122
123 if let Some(value) = find_duplicate_value(len, values) {
124 return exec_err!("map key must be unique, duplicate key found: {}", value);
125 }
126
127 Ok(())
128}
129
130fn validate_unique_binary_keys<'a>(
131 null_count: usize,
132 len: usize,
133 values: impl IntoIterator<Item = &'a [u8]>,
134) -> Result<()> {
135 if null_count > 0 {
136 return exec_err!("map key cannot be null");
137 }
138
139 if let Some(value) = find_duplicate_value(len, values) {
140 return exec_err!("map key must be unique, duplicate key found: {:?}", value);
141 }
142
143 Ok(())
144}
145
146fn find_duplicate_value<T, I>(len: usize, values: I) -> Option<T>
147where
148 T: Copy + Eq + Hash,
149 I: IntoIterator<Item = T>,
150{
151 let mut seen_keys = HashSet::with_capacity(len);
152 values.into_iter().find(|value| !seen_keys.insert(*value))
153}
154
155fn validate_unique_keys_generic(array: &dyn Array) -> Result<()> {
156 let mut seen_keys = HashSet::with_capacity(array.len());
157
158 for i in 0..array.len() {
159 let key = ScalarValue::try_from_array(array, i)?;
160
161 if key.is_null() {
163 return exec_err!("map key cannot be null");
164 }
165
166 if seen_keys.contains(&key) {
168 return exec_err!("map key must be unique, duplicate key found: {}", key);
169 }
170 seen_keys.insert(key);
171 }
172 Ok(())
173}
174
175fn validate_map_keys(array: &dyn Array) -> Result<()> {
177 match array.data_type() {
178 DataType::Int8 => validate_unique_primitive_keys::<Int8Type>(array),
179 DataType::Int16 => validate_unique_primitive_keys::<Int16Type>(array),
180 DataType::Int32 => validate_unique_primitive_keys::<Int32Type>(array),
181 DataType::Int64 => validate_unique_primitive_keys::<Int64Type>(array),
182 DataType::UInt8 => validate_unique_primitive_keys::<UInt8Type>(array),
183 DataType::UInt16 => validate_unique_primitive_keys::<UInt16Type>(array),
184 DataType::UInt32 => validate_unique_primitive_keys::<UInt32Type>(array),
185 DataType::UInt64 => validate_unique_primitive_keys::<UInt64Type>(array),
186 DataType::Date32 => validate_unique_primitive_keys::<Date32Type>(array),
187 DataType::Date64 => validate_unique_primitive_keys::<Date64Type>(array),
188 DataType::Utf8 => {
189 let arr = array.as_string::<i32>();
190 validate_unique_str_keys(arr.null_count(), arr.len(), arr.iter().flatten())
191 }
192 DataType::LargeUtf8 => {
193 let arr = array.as_string::<i64>();
194 validate_unique_str_keys(arr.null_count(), arr.len(), arr.iter().flatten())
195 }
196 DataType::Utf8View => {
197 let arr = array.as_string_view();
198 validate_unique_str_keys(arr.null_count(), arr.len(), arr.iter().flatten())
199 }
200 DataType::Binary => {
201 let arr = array.as_binary::<i32>();
202 validate_unique_binary_keys(arr.null_count(), arr.len(), arr.iter().flatten())
203 }
204 DataType::LargeBinary => {
205 let arr = array.as_binary::<i64>();
206 validate_unique_binary_keys(arr.null_count(), arr.len(), arr.iter().flatten())
207 }
208 DataType::BinaryView => {
209 let arr = array.as_binary_view();
210 validate_unique_binary_keys(arr.null_count(), arr.len(), arr.iter().flatten())
211 }
212 _ => validate_unique_keys_generic(array),
213 }
214}
215
216fn validate_map_keys_for_data_type(
217 keys: &ArrayRef,
218 keys_data_type: &DataType,
219 can_evaluate_to_const: bool,
220) -> Result<()> {
221 if can_evaluate_to_const {
222 return validate_map_keys(keys.as_ref());
223 }
224
225 match keys_data_type {
226 DataType::List(_) => keys
227 .as_list::<i32>()
228 .iter()
229 .flatten()
230 .try_for_each(|row| validate_map_keys(row.as_ref())),
231 DataType::LargeList(_) => keys
232 .as_list::<i64>()
233 .iter()
234 .flatten()
235 .try_for_each(|row| validate_map_keys(row.as_ref())),
236 DataType::FixedSizeList(_, _) => keys
237 .as_fixed_size_list()
238 .iter()
239 .flatten()
240 .try_for_each(|row| validate_map_keys(row.as_ref())),
241 data_type => exec_err!(
242 "Expected list, large_list or fixed_size_list, got {:?}",
243 data_type
244 ),
245 }
246}
247
248fn get_first_array_ref(columnar_value: &ColumnarValue) -> Result<ArrayRef> {
249 match columnar_value {
250 ColumnarValue::Scalar(value) => match value {
251 ScalarValue::List(array) => Ok(array.value(0)),
252 ScalarValue::LargeList(array) => Ok(array.value(0)),
253 ScalarValue::FixedSizeList(array) => Ok(array.value(0)),
254 _ => exec_err!("Expected array, got {}", value),
255 },
256 ColumnarValue::Array(array) => Ok(array.to_owned()),
257 }
258}
259
260fn make_map_batch_internal(
261 keys: &ArrayRef,
262 values: &ArrayRef,
263 can_evaluate_to_const: bool,
264 data_type: &DataType,
265) -> Result<ColumnarValue> {
266 if keys.len() != values.len() {
267 return exec_err!("map requires key and value lists to have the same length");
268 }
269
270 if !can_evaluate_to_const || keys.null_count() > 0 {
274 return match data_type {
275 DataType::LargeList(..) => make_map_array_internal::<i64>(keys, values),
276 DataType::List(..) => make_map_array_internal::<i32>(keys, values),
277 DataType::FixedSizeList(..) => {
278 make_map_array_from_fixed_size_list(keys, values)
280 }
281 _ => exec_err!(
282 "Expected List, LargeList, or FixedSizeList, got {:?}",
283 data_type
284 ),
285 };
286 }
287
288 let key_field = Arc::new(Field::new("key", keys.data_type().clone(), false));
289 let value_field = Arc::new(Field::new("value", values.data_type().clone(), true));
290 let mut entry_struct_buffer: VecDeque<(Arc<Field>, ArrayRef)> = VecDeque::new();
291 let mut entry_offsets_buffer = VecDeque::new();
292 entry_offsets_buffer.push_back(0);
293
294 entry_struct_buffer.push_back((Arc::clone(&key_field), Arc::clone(keys)));
295 entry_struct_buffer.push_back((Arc::clone(&value_field), Arc::clone(values)));
296 entry_offsets_buffer.push_back(keys.len() as u32);
297
298 let entry_struct: Vec<(Arc<Field>, ArrayRef)> = entry_struct_buffer.into();
299 let entry_struct = StructArray::from(entry_struct);
300
301 let map_data_type = DataType::Map(
302 Arc::new(Field::new(
303 "entries",
304 entry_struct.data_type().clone(),
305 false,
306 )),
307 false,
308 );
309
310 let entry_offsets: Vec<u32> = entry_offsets_buffer.into();
311 let entry_offsets_buffer = Buffer::from(entry_offsets.to_byte_slice());
312
313 let map_data = ArrayData::builder(map_data_type)
314 .len(entry_offsets.len() - 1)
315 .add_buffer(entry_offsets_buffer)
316 .add_child_data(entry_struct.to_data())
317 .build()?;
318 let map_array = Arc::new(MapArray::from(map_data));
319
320 Ok(if can_evaluate_to_const {
321 ColumnarValue::Scalar(ScalarValue::try_from_array(map_array.as_ref(), 0)?)
322 } else {
323 ColumnarValue::Array(map_array)
324 })
325}
326
327#[user_doc(
328 doc_section(label = "Map Functions"),
329 description = "Returns an Arrow map with the specified key-value pairs.\n\n\
330 The `make_map` function creates a map from two lists: one for keys and one for values. Each key must be unique and non-null.",
331 syntax_example = "map(key, value)\nmap {key: value}\nmake_map(['key1', 'key2'], ['value1', 'value2'])",
332 sql_example = r#"
333```sql
334-- Using map function
335SELECT MAP('type', 'test');
336----
337{type: test}
338
339SELECT MAP(['POST', 'HEAD', 'PATCH'], [41, 33, null]);
340----
341{POST: 41, HEAD: 33, PATCH: NULL}
342
343SELECT MAP([[1,2], [3,4]], ['a', 'b']);
344----
345{[1, 2]: a, [3, 4]: b}
346
347SELECT MAP { 'a': 1, 'b': 2 };
348----
349{a: 1, b: 2}
350
351-- Using make_map function
352SELECT MAKE_MAP(['POST', 'HEAD'], [41, 33]);
353----
354{POST: 41, HEAD: 33}
355
356SELECT MAKE_MAP(['key1', 'key2'], ['value1', null]);
357----
358{key1: value1, key2: }
359```"#,
360 argument(
361 name = "key",
362 description = "For `map`: Expression to be used for key. Can be a constant, column, function, or any combination of arithmetic or string operators.\n\
363 For `make_map`: The list of keys to be used in the map. Each key must be unique and non-null."
364 ),
365 argument(
366 name = "value",
367 description = "For `map`: Expression to be used for value. Can be a constant, column, function, or any combination of arithmetic or string operators.\n\
368 For `make_map`: The list of values to be mapped to the corresponding keys."
369 )
370)]
371#[derive(Debug, PartialEq, Eq, Hash)]
372pub struct MapFunc {
373 signature: Signature,
374}
375
376impl Default for MapFunc {
377 fn default() -> Self {
378 Self::new()
379 }
380}
381
382impl MapFunc {
383 pub fn new() -> Self {
384 Self {
385 signature: Signature::variadic_any(Volatility::Immutable),
386 }
387 }
388}
389
390impl ScalarUDFImpl for MapFunc {
391 fn name(&self) -> &str {
392 "map"
393 }
394
395 fn signature(&self) -> &Signature {
396 &self.signature
397 }
398
399 fn return_type(&self, arg_types: &[DataType]) -> Result<DataType> {
400 let [keys_arg, values_arg] = take_function_args(self.name(), arg_types)?;
401 let mut builder = SchemaBuilder::new();
402 builder.push(Field::new(
403 "key",
404 get_element_type(keys_arg)?.clone(),
405 false,
406 ));
407 builder.push(Field::new(
408 "value",
409 get_element_type(values_arg)?.clone(),
410 true,
411 ));
412 let fields = builder.finish().fields;
413 Ok(DataType::Map(
414 Arc::new(Field::new("entries", DataType::Struct(fields), false)),
415 false,
416 ))
417 }
418
419 fn invoke_with_args(&self, args: ScalarFunctionArgs) -> Result<ColumnarValue> {
420 make_map_batch(args.args, args.number_rows)
421 }
422
423 fn documentation(&self) -> Option<&Documentation> {
424 self.doc()
425 }
426}
427
428fn get_element_type(data_type: &DataType) -> Result<&DataType> {
429 match data_type {
430 DataType::List(element) => Ok(element.data_type()),
431 DataType::LargeList(element) => Ok(element.data_type()),
432 DataType::FixedSizeList(element, _) => Ok(element.data_type()),
433 _ => exec_err!(
434 "Expected list, large_list or fixed_size_list, got {:?}",
435 data_type
436 ),
437 }
438}
439
440fn make_map_array_internal<O: OffsetSizeTrait>(
496 keys: &ArrayRef,
497 values: &ArrayRef,
498) -> Result<ColumnarValue> {
499 let keys_data_type = keys.data_type().clone();
501 let values_data_type = values.data_type().clone();
502 let original_len = keys.len(); let nulls_bitmap = keys.nulls().cloned();
507
508 let keys = list_to_arrays::<O>(keys);
509 let values = list_to_arrays_skipping_null_rows::<O>(values, nulls_bitmap.as_ref());
510
511 build_map_array(
512 &keys,
513 &values,
514 &keys_data_type,
515 &values_data_type,
516 original_len,
517 nulls_bitmap,
518 )
519}
520
521fn make_map_array_from_fixed_size_list(
524 keys: &ArrayRef,
525 values: &ArrayRef,
526) -> Result<ColumnarValue> {
527 let keys_data_type = keys.data_type().clone();
529 let values_data_type = values.data_type().clone();
530 let original_len = keys.len();
531
532 let nulls_bitmap = keys.nulls().cloned();
534
535 let keys = fixed_size_list_to_arrays(keys);
536 let values =
537 fixed_size_list_to_arrays_skipping_null_rows(values, nulls_bitmap.as_ref());
538
539 build_map_array(
540 &keys,
541 &values,
542 &keys_data_type,
543 &values_data_type,
544 original_len,
545 nulls_bitmap,
546 )
547}
548fn list_to_arrays_skipping_null_rows<O: OffsetSizeTrait>(
549 array: &ArrayRef,
550 null_rows: Option<&arrow::buffer::NullBuffer>,
551) -> Vec<ArrayRef> {
552 array
553 .as_list::<O>()
554 .iter()
555 .enumerate()
556 .filter_map(|(i, row)| {
557 if null_rows.is_some_and(|nulls| nulls.is_null(i)) {
558 None
559 } else {
560 row
561 }
562 })
563 .collect()
564}
565
566fn fixed_size_list_to_arrays_skipping_null_rows(
567 array: &ArrayRef,
568 null_rows: Option<&arrow::buffer::NullBuffer>,
569) -> Vec<ArrayRef> {
570 array
571 .as_fixed_size_list()
572 .iter()
573 .enumerate()
574 .filter_map(|(i, row)| {
575 if null_rows.is_some_and(|nulls| nulls.is_null(i)) {
576 None
577 } else {
578 row
579 }
580 })
581 .collect()
582}
583
584fn build_map_array(
586 keys: &[ArrayRef],
587 values: &[ArrayRef],
588 keys_data_type: &DataType,
589 values_data_type: &DataType,
590 original_len: usize,
591 nulls_bitmap: Option<arrow::buffer::NullBuffer>,
592) -> Result<ColumnarValue> {
593 if keys.len() != values.len() {
594 return exec_err!("map requires key and value lists to have the same length");
595 }
596
597 let mut key_array_vec = vec![];
598 let mut value_array_vec = vec![];
599 for (k, v) in keys.iter().zip(values.iter()) {
600 key_array_vec.push(k.as_ref());
601 value_array_vec.push(v.as_ref());
602 }
603
604 let mut running_offset = 0i32;
609 let mut offset_buffer = vec![running_offset];
610 let mut non_null_idx = 0;
611 for i in 0..original_len {
612 let is_null = nulls_bitmap.as_ref().is_some_and(|nulls| nulls.is_null(i));
613 if !is_null {
614 let entry_count = keys[non_null_idx].len();
615 let entry_count_i32 = i32::try_from(entry_count).map_err(|_| {
617 datafusion_common::DataFusionError::Execution(format!(
618 "Map offset overflow: entry count {entry_count} at index {i} exceeds i32::MAX",
619 ))
620 })?;
621 running_offset =
622 running_offset.checked_add(entry_count_i32).ok_or_else(|| {
623 datafusion_common::DataFusionError::Execution(format!(
624 "Map offset overflow: cumulative offset exceeds i32::MAX at index {i}",
625 ))
626 })?;
627 non_null_idx += 1;
628 }
629 offset_buffer.push(running_offset);
630 }
631
632 let (flattened_keys, flattened_values) = if key_array_vec.is_empty() {
636 let key_type = get_element_type(keys_data_type)?;
639 let value_type = get_element_type(values_data_type)?;
640
641 (
642 arrow::array::new_empty_array(key_type),
643 arrow::array::new_empty_array(value_type),
644 )
645 } else {
646 let flattened_keys = arrow::compute::concat(key_array_vec.as_ref())?;
647 if flattened_keys.null_count() > 0 {
648 return exec_err!("keys cannot be null");
649 }
650 let flattened_values = arrow::compute::concat(value_array_vec.as_ref())?;
651 (flattened_keys, flattened_values)
652 };
653
654 let fields = vec![
655 Arc::new(Field::new("key", flattened_keys.data_type().clone(), false)),
656 Arc::new(Field::new(
657 "value",
658 flattened_values.data_type().clone(),
659 true,
660 )),
661 ];
662
663 let struct_data = ArrayData::builder(DataType::Struct(fields.into()))
664 .len(flattened_keys.len())
665 .add_child_data(flattened_keys.to_data())
666 .add_child_data(flattened_values.to_data())
667 .build()?;
668
669 let mut map_data_builder = ArrayData::builder(DataType::Map(
670 Arc::new(Field::new(
671 "entries",
672 struct_data.data_type().clone(),
673 false,
674 )),
675 false,
676 ))
677 .len(original_len) .add_child_data(struct_data)
679 .add_buffer(Buffer::from_slice_ref(offset_buffer.as_slice()));
680
681 if let Some(nulls) = nulls_bitmap {
683 map_data_builder = map_data_builder.nulls(Some(nulls));
684 }
685
686 let map_data = map_data_builder.build()?;
687 Ok(ColumnarValue::Array(Arc::new(MapArray::from(map_data))))
688}
689
690#[cfg(test)]
691mod tests {
692 use super::*;
693 #[test]
694 fn test_make_map_with_null_maps() {
695 let mut key_builder =
706 arrow::array::ListBuilder::new(arrow::array::StringBuilder::new());
707
708 key_builder.values().append_value("a");
710 key_builder.append(true);
711
712 key_builder.append(false);
714
715 key_builder.values().append_value("b");
717 key_builder.append(true);
718
719 let keys_array = Arc::new(key_builder.finish());
720
721 let mut value_builder =
723 arrow::array::ListBuilder::new(arrow::array::Int32Builder::new());
724
725 value_builder.values().append_value(1);
726 value_builder.append(true);
727
728 value_builder.values().append_value(2);
729 value_builder.append(true);
730
731 value_builder.values().append_value(3);
732 value_builder.append(true);
733
734 let values_array = Arc::new(value_builder.finish());
735
736 let result = make_map_batch(
738 vec![
739 ColumnarValue::Array(keys_array),
740 ColumnarValue::Array(values_array),
741 ],
742 3,
743 );
744
745 assert!(result.is_ok(), "Should handle NULL maps correctly");
746
747 let map_array = match result.unwrap() {
749 ColumnarValue::Array(arr) => arr,
750 _ => panic!("Expected Array result"),
751 };
752
753 assert_eq!(map_array.len(), 3, "Should have 3 maps");
754 assert!(!map_array.is_null(0), "First map should not be NULL");
755 assert!(map_array.is_null(1), "Second map should be NULL");
756 assert!(!map_array.is_null(2), "Third map should not be NULL");
757 }
758
759 #[test]
760 fn test_make_map_with_null_key_within_map_should_fail() {
761 let mut key_builder =
767 arrow::array::ListBuilder::new(arrow::array::StringBuilder::new());
768
769 key_builder.values().append_value("a");
770 key_builder.values().append_null(); key_builder.values().append_value("b");
772 key_builder.append(true);
773
774 let keys_array = Arc::new(key_builder.finish());
775
776 let mut value_builder =
778 arrow::array::ListBuilder::new(arrow::array::Int32Builder::new());
779
780 value_builder.values().append_value(1);
781 value_builder.values().append_value(2);
782 value_builder.values().append_value(3);
783 value_builder.append(true);
784
785 let values_array = Arc::new(value_builder.finish());
786
787 let result = make_map_batch(
789 vec![
790 ColumnarValue::Array(keys_array),
791 ColumnarValue::Array(values_array),
792 ],
793 1,
794 );
795
796 assert!(result.is_err(), "Should reject null keys within maps");
797
798 let err_msg = result.unwrap_err().to_string();
799 assert!(
800 err_msg.contains("cannot be null"),
801 "Error should mention null keys, got: {err_msg}"
802 );
803 }
804
805 #[test]
806 fn test_make_map_with_large_list() {
807 let mut key_builder =
812 arrow::array::LargeListBuilder::new(arrow::array::StringBuilder::new());
813
814 key_builder.values().append_value("a");
816 key_builder.values().append_value("b");
817 key_builder.append(true);
818
819 key_builder.values().append_value("c");
821 key_builder.append(true);
822
823 let keys_array = Arc::new(key_builder.finish());
824
825 let mut value_builder =
827 arrow::array::LargeListBuilder::new(arrow::array::Int32Builder::new());
828
829 value_builder.values().append_value(1);
830 value_builder.values().append_value(2);
831 value_builder.append(true);
832
833 value_builder.values().append_value(3);
834 value_builder.append(true);
835
836 let values_array = Arc::new(value_builder.finish());
837
838 let result = make_map_batch(
840 vec![
841 ColumnarValue::Array(keys_array),
842 ColumnarValue::Array(values_array),
843 ],
844 2,
845 );
846
847 assert!(
848 result.is_ok(),
849 "Should handle LargeList inputs correctly: {:?}",
850 result.err()
851 );
852
853 let map_array = match result.unwrap() {
855 ColumnarValue::Array(arr) => arr,
856 _ => panic!("Expected Array result"),
857 };
858
859 assert_eq!(map_array.len(), 2, "Should have 2 maps");
860 assert!(!map_array.is_null(0), "First map should not be NULL");
861 assert!(!map_array.is_null(1), "Second map should not be NULL");
862 }
863
864 #[test]
865 fn test_make_map_with_fixed_size_list() {
866 use arrow::array::FixedSizeListBuilder;
870
871 let key_values_builder = arrow::array::StringBuilder::new();
873 let mut key_builder = FixedSizeListBuilder::new(key_values_builder, 2);
874
875 key_builder.values().append_value("a");
877 key_builder.values().append_value("b");
878 key_builder.append(true);
879
880 key_builder.values().append_null();
882 key_builder.values().append_null();
883 key_builder.append(false);
884
885 key_builder.values().append_value("c");
887 key_builder.values().append_value("d");
888 key_builder.append(true);
889
890 let keys_array = Arc::new(key_builder.finish());
891
892 let value_values_builder = arrow::array::Int32Builder::new();
895 let mut value_builder = FixedSizeListBuilder::new(value_values_builder, 2);
896
897 value_builder.values().append_value(1);
898 value_builder.values().append_value(2);
899 value_builder.append(true);
900
901 value_builder.values().append_value(99);
902 value_builder.values().append_value(100);
903 value_builder.append(true);
904
905 value_builder.values().append_value(3);
906 value_builder.values().append_value(4);
907 value_builder.append(true);
908
909 let values_array = Arc::new(value_builder.finish());
910
911 let result = make_map_batch(
913 vec![
914 ColumnarValue::Array(keys_array),
915 ColumnarValue::Array(values_array),
916 ],
917 3,
918 );
919
920 assert!(
921 result.is_ok(),
922 "Should handle FixedSizeList inputs correctly: {:?}",
923 result.err()
924 );
925
926 let map_array = match result.unwrap() {
928 ColumnarValue::Array(arr) => arr,
929 _ => panic!("Expected Array result"),
930 };
931
932 assert_eq!(map_array.len(), 3, "Should have 3 maps");
933 assert!(!map_array.is_null(0), "First map should not be NULL");
934 assert!(map_array.is_null(1), "Second map should be NULL");
935 assert!(!map_array.is_null(2), "Third map should not be NULL");
936 }
937}