1use std::sync::{Arc, OnceLock};
19
20use arrow::array::{
21 Array, BooleanArray, Capacities, MutableArrayData, Scalar, cast::AsArray, make_array,
22 make_comparator,
23};
24use arrow::compute::SortOptions;
25use arrow::datatypes::{DataType, Field, FieldRef};
26use arrow_buffer::NullBuffer;
27
28use datafusion_common::cast::{as_map_array, as_struct_array};
29use datafusion_common::{
30 Result, ScalarValue, exec_datafusion_err, exec_err, internal_err, plan_datafusion_err,
31};
32use datafusion_expr::expr::ScalarFunction;
33use datafusion_expr::simplify::ExprSimplifyResult;
34use datafusion_expr::{
35 ColumnarValue, Documentation, Expr, ExpressionPlacement, ReturnFieldArgs,
36 ScalarFunctionArgs, ScalarUDF, ScalarUDFImpl, Signature, Volatility,
37};
38use datafusion_macros::user_doc;
39
40use super::named_struct::NamedStructFunc;
41use super::r#struct::StructFunc;
42
43#[user_doc(
44 doc_section(label = "Other Functions"),
45 description = r#"Returns a field within a map or a struct with the given key.
46 Supports nested field access by providing multiple field names.
47 Note: most users invoke `get_field` indirectly via field access
48 syntax such as `my_struct_col['field_name']` which results in a call to
49 `get_field(my_struct_col, 'field_name')`.
50 Nested access like `my_struct['a']['b']` is optimized to a single call:
51 `get_field(my_struct, 'a', 'b')`."#,
52 syntax_example = "get_field(expression, field_name[, field_name2, ...])",
53 sql_example = r#"```sql
54> -- Access a field from a struct column
55> create table test( struct_col) as values
56 ({name: 'Alice', age: 30}),
57 ({name: 'Bob', age: 25});
58> select struct_col from test;
59+-----------------------------+
60| struct_col |
61+-----------------------------+
62| {name: Alice, age: 30} |
63| {name: Bob, age: 25} |
64+-----------------------------+
65> select struct_col['name'] as name from test;
66+-------+
67| name |
68+-------+
69| Alice |
70| Bob |
71+-------+
72
73> -- Nested field access with multiple arguments
74> create table test(struct_col) as values
75 ({outer: {inner_val: 42}});
76> select struct_col['outer']['inner_val'] as result from test;
77+--------+
78| result |
79+--------+
80| 42 |
81+--------+
82```"#,
83 argument(
84 name = "expression",
85 description = "The map or struct to retrieve a field from."
86 ),
87 argument(
88 name = "field_name",
89 description = "The field name(s) to access, in order for nested access. Must evaluate to strings."
90 )
91)]
92#[derive(Debug, PartialEq, Eq, Hash)]
93pub struct GetFieldFunc {
94 signature: Signature,
95}
96
97impl Default for GetFieldFunc {
98 fn default() -> Self {
99 Self::new()
100 }
101}
102
103fn process_map_array(
108 array: &dyn Array,
109 key_array: Arc<dyn Array>,
110) -> Result<ColumnarValue> {
111 let map_array = as_map_array(array)?;
112 let keys = if key_array.data_type().is_nested() {
113 let comparator = make_comparator(
114 map_array.keys().as_ref(),
115 key_array.as_ref(),
116 SortOptions::default(),
117 )?;
118 let len = map_array.keys().len().min(key_array.len());
119 let values = (0..len).map(|i| comparator(i, i).is_eq()).collect();
120 let nulls = NullBuffer::union(map_array.keys().nulls(), key_array.nulls());
121 BooleanArray::new(values, nulls)
122 } else {
123 let be_compared = Scalar::new(key_array);
124 arrow::compute::kernels::cmp::eq(&be_compared, map_array.keys())?
125 };
126
127 let original_data = map_array.entries().column(1).to_data();
128 let capacity = Capacities::Array(original_data.len());
129 let mut mutable =
130 MutableArrayData::with_capacities(vec![&original_data], true, capacity);
131
132 let offsets = map_array.value_offsets();
133 let matches = keys.values();
137
138 for entry in 0..map_array.len() {
139 let start = offsets[entry] as usize;
140 let end = offsets[entry + 1] as usize;
141
142 let matched = (start..end).find(|&i| matches.value(i));
143
144 match matched {
145 Some(i) => mutable.try_extend(0, i, i + 1)?,
146 None => mutable.try_extend_nulls(1)?,
147 }
148 }
149
150 let data = mutable.freeze();
151 let data = make_array(data);
152 Ok(ColumnarValue::Array(data))
153}
154
155fn process_map_with_nested_key(
160 array: &dyn Array,
161 key_array: &dyn Array,
162) -> Result<ColumnarValue> {
163 let map_array = as_map_array(array)?;
164
165 let comparator =
166 make_comparator(map_array.keys().as_ref(), key_array, SortOptions::default())?;
167
168 let original_data = map_array.entries().column(1).to_data();
169 let capacity = Capacities::Array(original_data.len());
170 let mut mutable =
171 MutableArrayData::with_capacities(vec![&original_data], true, capacity);
172
173 for entry in 0..map_array.len() {
174 let start = map_array.value_offsets()[entry] as usize;
175 let end = map_array.value_offsets()[entry + 1] as usize;
176
177 let mut found_match = false;
178 for i in start..end {
179 if comparator(i, 0).is_eq() {
180 mutable.try_extend(0, i, i + 1)?;
181 found_match = true;
182 break;
183 }
184 }
185
186 if !found_match {
187 mutable.try_extend_nulls(1)?;
188 }
189 }
190
191 let data = mutable.freeze();
192 let data = make_array(data);
193 Ok(ColumnarValue::Array(data))
194}
195
196fn extract_single_field(base: ColumnarValue, name: ScalarValue) -> Result<ColumnarValue> {
198 let arrays = ColumnarValue::values_to_arrays(&[base])?;
199 let array = Arc::clone(&arrays[0]);
200
201 let string_value = name.try_as_str().flatten().map(|s| s.to_string());
202
203 match (array.data_type(), name, string_value) {
204 (DataType::Dictionary(_, value_type), _, Some(field_name))
208 if matches!(value_type.as_ref(), DataType::Struct(_)) =>
209 {
210 let dict = array.as_any_dictionary();
211 let values_struct = dict.values().as_struct();
212 let field_col =
213 values_struct.column_by_name(&field_name).ok_or_else(|| {
214 exec_datafusion_err!(
215 "Field {field_name} not found in dictionary struct"
216 )
217 })?;
218 Ok(ColumnarValue::Array(
219 dict.with_values(Arc::clone(field_col)),
220 ))
221 }
222 (DataType::Map(_, _), ScalarValue::List(arr), _) => {
223 let key_array: Arc<dyn Array> = arr;
224 process_map_array(&array, key_array)
225 }
226 (DataType::Map(_, _), ScalarValue::Struct(arr), _) => {
227 process_map_array(&array, arr as Arc<dyn Array>)
228 }
229 (DataType::Map(_, _), other, _) => {
230 let data_type = other.data_type();
231 if data_type.is_nested() {
232 process_map_with_nested_key(&array, &other.to_array()?)
233 } else {
234 process_map_array(&array, other.to_array()?)
235 }
236 }
237 (DataType::Struct(_), _, Some(k)) => {
238 let as_struct_array = as_struct_array(&array)?;
239 match as_struct_array.column_by_name(&k) {
240 None => exec_err!("Field {k} not found in struct"),
241 Some(col) => Ok(ColumnarValue::Array(Arc::clone(col))),
242 }
243 }
244 (DataType::Struct(_), name, _) => exec_err!(
245 "get_field is only possible on struct with utf8 indexes. \
246 Received with {name:?} index"
247 ),
248 (DataType::Null, _, _) => Ok(ColumnarValue::Scalar(ScalarValue::Null)),
249 (dt, name, _) => exec_err!(
250 "get_field is only possible on maps or structs. Received {dt} with {name:?} index"
251 ),
252 }
253}
254
255fn get_field_udf() -> Arc<ScalarUDF> {
258 static GET_FIELD_UDF: OnceLock<Arc<ScalarUDF>> = OnceLock::new();
259 Arc::clone(
260 GET_FIELD_UDF
261 .get_or_init(|| Arc::new(ScalarUDF::new_from_impl(GetFieldFunc::new()))),
262 )
263}
264
265fn simplify_get_field_over_struct_constructor(args: &[Expr]) -> Option<Expr> {
294 let [base, field_name, rest @ ..] = args else {
295 return None;
296 };
297
298 let Expr::Literal(field_name, _) = field_name else {
300 return None;
301 };
302 let field_name = field_name
303 .try_as_str()
304 .flatten()
305 .filter(|s| !s.is_empty())?;
306
307 let Expr::ScalarFunction(ScalarFunction {
308 func,
309 args: ctor_args,
310 }) = base
311 else {
312 return None;
313 };
314
315 let value = if func.inner().is::<NamedStructFunc>() {
316 if !ctor_args.len().is_multiple_of(2) {
318 return None;
319 }
320 let mut matched = None;
321 for pair in ctor_args.chunks_exact(2) {
322 let Expr::Literal(name, _) = &pair[0] else {
333 return None;
334 };
335 let name = name.try_as_str().flatten()?;
336 if matched.is_none() && name == field_name {
338 matched = Some(&pair[1]);
339 }
340 }
341 matched?.clone()
342 } else if func.inner().is::<StructFunc>() {
343 let index: usize = field_name.strip_prefix('c')?.parse().ok()?;
345 if format!("c{index}") != field_name {
347 return None;
348 }
349 ctor_args.get(index)?.clone()
350 } else {
351 return None;
352 };
353
354 if rest.is_empty() {
355 return Some(value);
356 }
357
358 let mut new_args = Vec::with_capacity(rest.len() + 1);
361 new_args.push(value);
362 new_args.extend_from_slice(rest);
363 Some(Expr::ScalarFunction(ScalarFunction::new_udf(
364 get_field_udf(),
365 new_args,
366 )))
367}
368
369impl GetFieldFunc {
370 pub fn new() -> Self {
371 Self {
372 signature: Signature::user_defined(Volatility::Immutable),
373 }
374 }
375}
376
377impl ScalarUDFImpl for GetFieldFunc {
379 fn name(&self) -> &str {
380 "get_field"
381 }
382
383 fn display_name(&self, args: &[Expr]) -> Result<String> {
384 if args.len() < 2 {
385 return exec_err!(
386 "get_field requires at least 2 arguments, got {}",
387 args.len()
388 );
389 }
390
391 let base = &args[0];
392 let field_names: Vec<String> = args[1..]
393 .iter()
394 .map(|f| match f {
395 Expr::Literal(name, _) => name.to_string(),
396 other => other.schema_name().to_string(),
397 })
398 .collect();
399
400 Ok(format!("{}[{}]", base, field_names.join("][")))
401 }
402
403 fn schema_name(&self, args: &[Expr]) -> Result<String> {
404 if args.len() < 2 {
405 return exec_err!(
406 "get_field requires at least 2 arguments, got {}",
407 args.len()
408 );
409 }
410
411 let base = &args[0];
412 let field_names: Vec<String> = args[1..]
413 .iter()
414 .map(|f| match f {
415 Expr::Literal(name, _) => name.to_string(),
416 other => other.schema_name().to_string(),
417 })
418 .collect();
419
420 Ok(format!(
421 "{}[{}]",
422 base.schema_name(),
423 field_names.join("][")
424 ))
425 }
426
427 fn signature(&self) -> &Signature {
428 &self.signature
429 }
430
431 fn return_type(&self, _: &[DataType]) -> Result<DataType> {
432 internal_err!("return_field_from_args should be called instead")
433 }
434
435 fn return_field_from_args(&self, args: ReturnFieldArgs) -> Result<FieldRef> {
436 if args.scalar_arguments.len() < 2 {
438 return exec_err!(
439 "get_field requires at least 2 arguments, got {}",
440 args.scalar_arguments.len()
441 );
442 }
443
444 let mut current_field = Arc::clone(&args.arg_fields[0]);
445
446 for (i, sv) in args.scalar_arguments.iter().enumerate().skip(1) {
448 match current_field.data_type() {
449 DataType::Map(map_field, _) => {
450 match map_field.data_type() {
451 DataType::Struct(fields) if fields.len() == 2 => {
452 let value_field = fields
457 .get(1)
458 .expect("fields should have exactly two members");
459
460 current_field = Arc::new(
461 value_field.as_ref().clone().with_nullable(true),
462 );
463 }
464 _ => {
465 return exec_err!(
466 "Map fields must contain a Struct with exactly 2 fields"
467 );
468 }
469 }
470 }
471 DataType::Dictionary(key_type, value_type)
475 if matches!(value_type.as_ref(), DataType::Struct(_)) =>
476 {
477 let DataType::Struct(fields) = value_type.as_ref() else {
478 unreachable!()
479 };
480 let field_name = sv
481 .as_ref()
482 .and_then(|sv| {
483 sv.try_as_str().flatten().filter(|s| !s.is_empty())
484 })
485 .ok_or_else(|| {
486 exec_datafusion_err!("Field name must be a non-empty string")
487 })?;
488
489 let child_field = fields
490 .iter()
491 .find(|f| f.name() == field_name)
492 .ok_or_else(|| {
493 plan_datafusion_err!("Field {field_name} not found in struct")
494 })?;
495
496 let dict_type = DataType::Dictionary(
497 key_type.clone(),
498 Box::new(child_field.data_type().clone()),
499 );
500 let mut new_field =
501 child_field.as_ref().clone().with_data_type(dict_type);
502 if current_field.is_nullable() {
503 new_field = new_field.with_nullable(true);
504 }
505 current_field = Arc::new(new_field);
506 }
507 DataType::Struct(fields) => {
508 let field_name = sv
509 .as_ref()
510 .and_then(|sv| {
511 sv.try_as_str().flatten().filter(|s| !s.is_empty())
512 })
513 .ok_or_else(|| {
514 datafusion_common::DataFusionError::Execution(
515 "Field name must be a non-empty string".to_string(),
516 )
517 })?;
518
519 let child_field = fields
520 .iter()
521 .find(|f| f.name() == field_name)
522 .ok_or_else(|| {
523 plan_datafusion_err!("Field {field_name} not found in struct")
524 })?;
525
526 let mut new_field = child_field.as_ref().clone();
527
528 if current_field.is_nullable() {
530 new_field = new_field.with_nullable(true);
531 }
532 current_field = Arc::new(new_field);
533 }
534 DataType::Null => {
535 return Ok(Field::new(self.name(), DataType::Null, true).into());
536 }
537 other => {
538 return exec_err!(
539 "Cannot access field at argument {}: type {} is not Struct, Map, or Null",
540 i,
541 other
542 );
543 }
544 }
545 }
546
547 Ok(current_field)
548 }
549
550 fn invoke_with_args(&self, args: ScalarFunctionArgs) -> Result<ColumnarValue> {
551 if args.args.len() < 2 {
552 return exec_err!(
553 "get_field requires at least 2 arguments, got {}",
554 args.args.len()
555 );
556 }
557
558 let mut current = args.args[0].clone();
559
560 if current.data_type().is_null() {
562 return Ok(ColumnarValue::Scalar(ScalarValue::Null));
563 }
564
565 for field_name in args.args.iter().skip(1) {
567 let field_name_scalar = match field_name {
568 ColumnarValue::Scalar(name) => name.clone(),
569 _ => {
570 return exec_err!(
571 "get_field function requires all field_name arguments to be scalars"
572 );
573 }
574 };
575
576 current = extract_single_field(current, field_name_scalar)?;
577
578 if current.data_type().is_null() {
580 return Ok(ColumnarValue::Scalar(ScalarValue::Null));
581 }
582 }
583
584 Ok(current)
585 }
586
587 fn simplify(
588 &self,
589 args: Vec<Expr>,
590 _info: &datafusion_expr::simplify::SimplifyContext,
591 ) -> Result<ExprSimplifyResult> {
592 if args.len() < 2 {
594 return Ok(ExprSimplifyResult::Original(args));
595 }
596
597 let mut path_args_stack = vec![&args[1..]];
603 let mut current_expr = &args[0];
604
605 let base_expr = loop {
607 if let Expr::ScalarFunction(ScalarFunction {
608 func,
609 args: inner_args,
610 }) = current_expr
611 && func.inner().is::<GetFieldFunc>()
612 {
613 path_args_stack.push(&inner_args[1..]);
615
616 current_expr = &inner_args[0];
618 continue;
619 }
620 break current_expr;
622 };
623
624 let did_flatten = path_args_stack.len() > 1;
626
627 let mut merged_args = vec![base_expr.clone()];
630 for path_slice in path_args_stack.iter().rev() {
631 merged_args.extend_from_slice(path_slice);
632 }
633
634 if let Some(simplified) = simplify_get_field_over_struct_constructor(&merged_args)
637 {
638 return Ok(ExprSimplifyResult::Simplified(simplified));
639 }
640
641 if did_flatten {
642 return Ok(ExprSimplifyResult::Simplified(Expr::ScalarFunction(
643 ScalarFunction::new_udf(get_field_udf(), merged_args),
644 )));
645 }
646
647 Ok(ExprSimplifyResult::Original(args))
648 }
649
650 fn coerce_types(&self, arg_types: &[DataType]) -> Result<Vec<DataType>> {
651 if arg_types.len() < 2 {
652 return exec_err!(
653 "get_field requires at least 2 arguments, got {}",
654 arg_types.len()
655 );
656 }
657 Ok(arg_types.to_vec())
659 }
660
661 fn documentation(&self) -> Option<&Documentation> {
662 self.doc()
663 }
664
665 fn placement(&self, args: &[ExpressionPlacement]) -> ExpressionPlacement {
666 if args.is_empty() {
670 return ExpressionPlacement::KeepInPlace;
671 }
672
673 let base_placement = args[0];
674 let base_is_pushable = matches!(
675 base_placement,
676 ExpressionPlacement::Column | ExpressionPlacement::MoveTowardsLeafNodes
677 );
678
679 let all_keys_are_literals = args
680 .iter()
681 .skip(1)
682 .all(|p| *p == ExpressionPlacement::Literal);
683
684 if base_is_pushable && all_keys_are_literals {
685 ExpressionPlacement::MoveTowardsLeafNodes
686 } else {
687 ExpressionPlacement::KeepInPlace
688 }
689 }
690}
691
692#[cfg(test)]
693mod tests {
694 use super::*;
695 use arrow::array::{ArrayRef, Int32Array, StructArray};
696 use arrow::datatypes::Fields;
697
698 #[test]
699 fn test_get_field_utf8view_key() -> Result<()> {
700 let a_values = Int32Array::from(vec![Some(1), Some(2), Some(3)]);
702 let b_values = Int32Array::from(vec![Some(10), Some(20), Some(30)]);
703
704 let fields: Fields = vec![
705 Field::new("a", DataType::Int32, true),
706 Field::new("b", DataType::Int32, true),
707 ]
708 .into();
709
710 let struct_array = StructArray::new(
711 fields,
712 vec![
713 Arc::new(a_values) as ArrayRef,
714 Arc::new(b_values) as ArrayRef,
715 ],
716 None,
717 );
718
719 let base = ColumnarValue::Array(Arc::new(struct_array));
720
721 let key = ScalarValue::Utf8View(Some("a".to_string()));
723
724 let result = extract_single_field(base, key)?;
725
726 let result_array = result.into_array(3)?;
727 let expected = Int32Array::from(vec![Some(1), Some(2), Some(3)]);
728
729 assert_eq!(result_array.as_ref(), &expected as &dyn Array);
730
731 Ok(())
732 }
733
734 #[test]
735 fn test_get_field_dict_encoded_struct() -> Result<()> {
736 use arrow::array::{DictionaryArray, StringArray, UInt32Array};
737 use arrow::datatypes::UInt32Type;
738
739 let names = Arc::new(StringArray::from(vec!["main", "foo", "bar"])) as ArrayRef;
740 let ids = Arc::new(Int32Array::from(vec![1, 2, 3])) as ArrayRef;
741
742 let struct_fields: Fields = vec![
743 Field::new("name", DataType::Utf8, false),
744 Field::new("id", DataType::Int32, false),
745 ]
746 .into();
747
748 let values_struct =
749 Arc::new(StructArray::new(struct_fields, vec![names, ids], None)) as ArrayRef;
750
751 let keys = UInt32Array::from(vec![0u32, 1, 2, 0, 1]);
752 let dict = DictionaryArray::<UInt32Type>::try_new(keys, values_struct)?;
753
754 let base = ColumnarValue::Array(Arc::new(dict));
755 let key = ScalarValue::Utf8(Some("name".to_string()));
756
757 let result = extract_single_field(base, key)?;
758 let result_array = result.into_array(5)?;
759
760 assert!(
761 matches!(result_array.data_type(), DataType::Dictionary(_, _)),
762 "expected dictionary output, got {:?}",
763 result_array.data_type()
764 );
765
766 let result_dict = result_array
767 .as_any()
768 .downcast_ref::<DictionaryArray<UInt32Type>>()
769 .unwrap();
770 assert_eq!(result_dict.values().len(), 3);
771 assert_eq!(result_dict.len(), 5);
772
773 let resolved = arrow::compute::cast(&result_array, &DataType::Utf8)?;
774 let string_arr = resolved.as_any().downcast_ref::<StringArray>().unwrap();
775 assert_eq!(string_arr.value(0), "main");
776 assert_eq!(string_arr.value(1), "foo");
777 assert_eq!(string_arr.value(2), "bar");
778 assert_eq!(string_arr.value(3), "main");
779 assert_eq!(string_arr.value(4), "foo");
780
781 Ok(())
782 }
783
784 #[test]
785 fn test_get_field_nested_dict_struct() -> Result<()> {
786 use arrow::array::{DictionaryArray, StringArray, UInt32Array};
787 use arrow::datatypes::UInt32Type;
788
789 let func_names = Arc::new(StringArray::from(vec!["main", "foo"])) as ArrayRef;
790 let func_files = Arc::new(StringArray::from(vec!["main.c", "foo.c"])) as ArrayRef;
791 let func_fields: Fields = vec![
792 Field::new("name", DataType::Utf8, false),
793 Field::new("file", DataType::Utf8, false),
794 ]
795 .into();
796 let func_struct = Arc::new(StructArray::new(
797 func_fields.clone(),
798 vec![func_names, func_files],
799 None,
800 )) as ArrayRef;
801 let func_dict = Arc::new(DictionaryArray::<UInt32Type>::try_new(
802 UInt32Array::from(vec![0u32, 1, 0]),
803 func_struct,
804 )?) as ArrayRef;
805
806 let line_nums = Arc::new(Int32Array::from(vec![10, 20, 30])) as ArrayRef;
807 let line_fields: Fields = vec![
808 Field::new("num", DataType::Int32, false),
809 Field::new(
810 "function",
811 DataType::Dictionary(
812 Box::new(DataType::UInt32),
813 Box::new(DataType::Struct(func_fields)),
814 ),
815 false,
816 ),
817 ]
818 .into();
819 let line_struct = StructArray::new(line_fields, vec![line_nums, func_dict], None);
820
821 let base = ColumnarValue::Array(Arc::new(line_struct));
822
823 let func_result =
824 extract_single_field(base, ScalarValue::Utf8(Some("function".to_string())))?;
825
826 let func_array = func_result.into_array(3)?;
827 assert!(
828 matches!(func_array.data_type(), DataType::Dictionary(_, _)),
829 "expected dictionary for function, got {:?}",
830 func_array.data_type()
831 );
832
833 let name_result = extract_single_field(
834 ColumnarValue::Array(func_array),
835 ScalarValue::Utf8(Some("name".to_string())),
836 )?;
837 let name_array = name_result.into_array(3)?;
838
839 assert!(
840 matches!(name_array.data_type(), DataType::Dictionary(_, _)),
841 "expected dictionary for name, got {:?}",
842 name_array.data_type()
843 );
844
845 let name_dict = name_array
846 .as_any()
847 .downcast_ref::<DictionaryArray<UInt32Type>>()
848 .unwrap();
849 assert_eq!(name_dict.values().len(), 2);
850 assert_eq!(name_dict.len(), 3);
851
852 let resolved = arrow::compute::cast(&name_array, &DataType::Utf8)?;
853 let strings = resolved.as_any().downcast_ref::<StringArray>().unwrap();
854 assert_eq!(strings.value(0), "main");
855 assert_eq!(strings.value(1), "foo");
856 assert_eq!(strings.value(2), "main");
857
858 Ok(())
859 }
860
861 #[test]
862 fn test_placement_literal_key() {
863 let func = GetFieldFunc::new();
864
865 let args = vec![ExpressionPlacement::Column, ExpressionPlacement::Literal];
867 assert_eq!(
868 func.placement(&args),
869 ExpressionPlacement::MoveTowardsLeafNodes
870 );
871
872 let args = vec![
874 ExpressionPlacement::Column,
875 ExpressionPlacement::Literal,
876 ExpressionPlacement::Literal,
877 ];
878 assert_eq!(
879 func.placement(&args),
880 ExpressionPlacement::MoveTowardsLeafNodes
881 );
882
883 let args = vec![
885 ExpressionPlacement::MoveTowardsLeafNodes,
886 ExpressionPlacement::Literal,
887 ];
888 assert_eq!(
889 func.placement(&args),
890 ExpressionPlacement::MoveTowardsLeafNodes
891 );
892 }
893
894 #[test]
895 fn test_placement_column_key() {
896 let func = GetFieldFunc::new();
897
898 let args = vec![ExpressionPlacement::Column, ExpressionPlacement::Column];
900 assert_eq!(func.placement(&args), ExpressionPlacement::KeepInPlace);
901
902 let args = vec![
904 ExpressionPlacement::Column,
905 ExpressionPlacement::Literal,
906 ExpressionPlacement::Column,
907 ];
908 assert_eq!(func.placement(&args), ExpressionPlacement::KeepInPlace);
909 }
910
911 #[test]
912 fn test_placement_root() {
913 let func = GetFieldFunc::new();
914
915 let args = vec![
917 ExpressionPlacement::KeepInPlace,
918 ExpressionPlacement::Literal,
919 ];
920 assert_eq!(func.placement(&args), ExpressionPlacement::KeepInPlace);
921
922 let args = vec![
924 ExpressionPlacement::Column,
925 ExpressionPlacement::KeepInPlace,
926 ];
927 assert_eq!(func.placement(&args), ExpressionPlacement::KeepInPlace);
928 }
929
930 #[test]
931 fn test_placement_edge_cases() {
932 let func = GetFieldFunc::new();
933
934 assert_eq!(func.placement(&[]), ExpressionPlacement::KeepInPlace);
936
937 let args = vec![ExpressionPlacement::Column];
939 assert_eq!(
940 func.placement(&args),
941 ExpressionPlacement::MoveTowardsLeafNodes
942 );
943
944 let args = vec![ExpressionPlacement::Literal, ExpressionPlacement::Literal];
946 assert_eq!(func.placement(&args), ExpressionPlacement::KeepInPlace);
947 }
948
949 use datafusion_common::Column;
952 use datafusion_expr::simplify::SimplifyContext;
953
954 fn lit_str(s: &str) -> Expr {
956 Expr::Literal(ScalarValue::Utf8(Some(s.to_string())), None)
957 }
958
959 fn col(name: &str) -> Expr {
961 Expr::Column(Column::from_name(name))
962 }
963
964 fn scalar_fn(udf: ScalarUDF, args: Vec<Expr>) -> Expr {
965 Expr::ScalarFunction(ScalarFunction::new_udf(Arc::new(udf), args))
966 }
967
968 fn named_struct(pairs: Vec<(&str, Expr)>) -> Expr {
970 let args = pairs
971 .into_iter()
972 .flat_map(|(name, value)| [lit_str(name), value])
973 .collect();
974 scalar_fn(ScalarUDF::new_from_impl(NamedStructFunc::new()), args)
975 }
976
977 fn struct_fn(values: Vec<Expr>) -> Expr {
979 scalar_fn(ScalarUDF::new_from_impl(StructFunc::new()), values)
980 }
981
982 fn get_field(args: Vec<Expr>) -> Expr {
984 scalar_fn(ScalarUDF::new_from_impl(GetFieldFunc::new()), args)
985 }
986
987 fn simplified(args: Vec<Expr>) -> Expr {
990 match GetFieldFunc::new()
991 .simplify(args, &SimplifyContext::default())
992 .unwrap()
993 {
994 ExprSimplifyResult::Simplified(expr) => expr,
995 ExprSimplifyResult::Original(args) => {
996 panic!("expected the expression to be simplified, got {args:?}")
997 }
998 }
999 }
1000
1001 fn assert_not_simplified(args: Vec<Expr>) {
1003 match GetFieldFunc::new()
1004 .simplify(args.clone(), &SimplifyContext::default())
1005 .unwrap()
1006 {
1007 ExprSimplifyResult::Original(unchanged) => assert_eq!(unchanged, args),
1008 ExprSimplifyResult::Simplified(expr) => {
1009 panic!("expected no simplification, got {expr:?}")
1010 }
1011 }
1012 }
1013
1014 #[test]
1015 fn simplify_get_field_named_struct_returns_matching_value() {
1016 let args = vec![
1018 named_struct(vec![("min", col("a")), ("max", col("b"))]),
1019 lit_str("max"),
1020 ];
1021 assert_eq!(simplified(args), col("b"));
1022 }
1023
1024 #[test]
1025 fn simplify_get_field_named_struct_first_field() {
1026 let args = vec![
1028 named_struct(vec![("min", col("a")), ("max", col("b"))]),
1029 lit_str("min"),
1030 ];
1031 assert_eq!(simplified(args), col("a"));
1032 }
1033
1034 #[test]
1035 fn simplify_get_field_named_struct_duplicate_names_picks_first() {
1036 let args = vec![
1038 named_struct(vec![("k", col("a")), ("k", col("b"))]),
1039 lit_str("k"),
1040 ];
1041 assert_eq!(simplified(args), col("a"));
1042 }
1043
1044 #[test]
1045 fn simplify_get_field_struct_positional() {
1046 let args = vec![struct_fn(vec![col("a"), col("b")]), lit_str("c1")];
1048 assert_eq!(simplified(args), col("b"));
1049 }
1050
1051 #[test]
1052 fn simplify_get_field_nested_named_struct() {
1053 let args = vec![
1057 named_struct(vec![("s", named_struct(vec![("k", col("x"))]))]),
1058 lit_str("s"),
1059 lit_str("k"),
1060 ];
1061 let first_pass = simplified(args);
1062 let Expr::ScalarFunction(ScalarFunction { args, .. }) = first_pass else {
1063 panic!("expected a get_field call after the first pass")
1064 };
1065 assert_eq!(simplified(args), col("x"));
1066 }
1067
1068 #[test]
1069 fn simplify_get_field_flattens_then_resolves_named_struct() {
1070 let args = vec![
1073 get_field(vec![
1074 named_struct(vec![("s", named_struct(vec![("k", col("x"))]))]),
1075 lit_str("s"),
1076 ]),
1077 lit_str("k"),
1078 ];
1079 let expected = get_field(vec![named_struct(vec![("k", col("x"))]), lit_str("k")]);
1080 assert_eq!(simplified(args), expected);
1081 }
1082
1083 #[test]
1084 fn simplify_get_field_dynamic_field_name_left_alone() {
1085 let args = vec![named_struct(vec![("a", col("x"))]), col("field_name")];
1087 assert_not_simplified(args);
1088 }
1089
1090 #[test]
1091 fn simplify_get_field_null_field_name_left_alone() {
1092 let null_field_name = Expr::Literal(ScalarValue::Utf8(None), None);
1095 let args = vec![named_struct(vec![("a", col("x"))]), null_field_name];
1096 assert_not_simplified(args);
1097 }
1098
1099 #[test]
1100 fn simplify_get_field_dynamic_struct_name_left_alone() {
1101 let named_struct_with_dynamic_name = scalar_fn(
1104 ScalarUDF::new_from_impl(NamedStructFunc::new()),
1105 vec![col("dynamic_name"), col("x")],
1106 );
1107 let args = vec![named_struct_with_dynamic_name, lit_str("a")];
1108 assert_not_simplified(args);
1109 }
1110
1111 #[test]
1112 fn simplify_get_field_missing_field_left_alone() {
1113 let args = vec![named_struct(vec![("a", col("x"))]), lit_str("missing")];
1115 assert_not_simplified(args);
1116 }
1117
1118 #[test]
1119 fn simplify_get_field_non_canonical_struct_field_left_alone() {
1120 let args = vec![struct_fn(vec![col("a"), col("b")]), lit_str("c01")];
1122 assert_not_simplified(args);
1123 }
1124
1125 #[test]
1126 fn simplify_get_field_column_base_left_alone() {
1127 let args = vec![col("s"), lit_str("a")];
1129 assert_not_simplified(args);
1130 }
1131}