From d0e3e1d8a6cbfb4a2524d9b687ecca224c032e9f Mon Sep 17 00:00:00 2001 From: Matthew Kim <38759997+friendlymatthew@users.noreply.github.com> Date: Mon, 24 Nov 2025 12:03:49 -0500 Subject: [PATCH 1/2] Fix bug --- datafusion/sql/src/expr/function.rs | 27 +++++++++++++++++++++- datafusion/sqllogictest/test_files/map.slt | 5 ++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/datafusion/sql/src/expr/function.rs b/datafusion/sql/src/expr/function.rs index e993f1ceee88..5aa03e964de1 100644 --- a/datafusion/sql/src/expr/function.rs +++ b/datafusion/sql/src/expr/function.rs @@ -266,7 +266,32 @@ impl SqlToRel<'_, S> { } }; - if name.eq("make_map") { + // handle make_map and map functions + // make_map always uses plan_make_map: make_map(k1, v1, k2, v2, ...) + // map has 2 syntaxes: + // 1. map([keys], [values]) - two arrays that get zipped + // 2. map(k1, v1, k2, v2, ...) - variadic pairs (uses plan_make_map) + let use_plan_make_map = match name.as_str() { + "make_map" => true, + "map" => { + // for map, check if this is the first syntax variant (two-array) + let args = + self.function_args_to_expr(args.clone(), schema, planner_context)?; + + let is_two_array_syntax = args.len() == 2 + && args.iter().all(|arg| match arg.get_type(schema) { + Ok(DataType::List(_)) + | Ok(DataType::LargeList(_)) + | Ok(DataType::FixedSizeList(_, _)) => true, + _ => false, + }); + + !is_two_array_syntax + } + _ => false, + }; + + if use_plan_make_map { let mut fn_args = self.function_args_to_expr(args.clone(), schema, planner_context)?; for planner in self.context_provider.get_expr_planners().iter() { diff --git a/datafusion/sqllogictest/test_files/map.slt b/datafusion/sqllogictest/test_files/map.slt index fa8e9ad3c537..78f2f6698269 100644 --- a/datafusion/sqllogictest/test_files/map.slt +++ b/datafusion/sqllogictest/test_files/map.slt @@ -174,6 +174,11 @@ SELECT MAP(['POST', 'HEAD', 'PATCH'], [41, 33, 30]); ---- {POST: 41, HEAD: 33, PATCH: 30} +query ? +SELECT MAP('type', 'test'); +---- +{type: test} + query ? SELECT MAP(['POST', 'HEAD', 'PATCH'], [41, 33, null]); ---- From 81d970deb530b800fc0ce8b3e2f5b2907024e684 Mon Sep 17 00:00:00 2001 From: Matthew Kim <38759997+friendlymatthew@users.noreply.github.com> Date: Mon, 24 Nov 2025 13:43:01 -0500 Subject: [PATCH 2/2] Add additional SLT test case --- datafusion/sql/src/expr/function.rs | 20 +++++++++++++++----- datafusion/sqllogictest/test_files/map.slt | 15 ++++++++++++--- 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/datafusion/sql/src/expr/function.rs b/datafusion/sql/src/expr/function.rs index 5aa03e964de1..badeab46c837 100644 --- a/datafusion/sql/src/expr/function.rs +++ b/datafusion/sql/src/expr/function.rs @@ -279,13 +279,22 @@ impl SqlToRel<'_, S> { self.function_args_to_expr(args.clone(), schema, planner_context)?; let is_two_array_syntax = args.len() == 2 - && args.iter().all(|arg| match arg.get_type(schema) { - Ok(DataType::List(_)) - | Ok(DataType::LargeList(_)) - | Ok(DataType::FixedSizeList(_, _)) => true, - _ => false, + && args.iter().all(|arg| { + matches!( + arg.get_type(schema), + Ok(DataType::List(_)) + | Ok(DataType::LargeList(_)) + | Ok(DataType::FixedSizeList(_, _)) + ) }); + // map function with variadic syntax requires non-empty list of arguments + if !is_two_array_syntax && args.is_empty() { + return plan_err!( + "Function 'map' expected at least one argument but received 0" + ); + } + !is_two_array_syntax } _ => false, @@ -294,6 +303,7 @@ impl SqlToRel<'_, S> { if use_plan_make_map { let mut fn_args = self.function_args_to_expr(args.clone(), schema, planner_context)?; + for planner in self.context_provider.get_expr_planners().iter() { match planner.plan_make_map(fn_args)? { PlannerResult::Planned(expr) => return Ok(expr), diff --git a/datafusion/sqllogictest/test_files/map.slt b/datafusion/sqllogictest/test_files/map.slt index 78f2f6698269..21fa72ad86f1 100644 --- a/datafusion/sqllogictest/test_files/map.slt +++ b/datafusion/sqllogictest/test_files/map.slt @@ -179,6 +179,11 @@ SELECT MAP('type', 'test'); ---- {type: test} +query ? +SELECT MAP('a', 2, 'b', 3); +---- +{a: 2, b: 3} + query ? SELECT MAP(['POST', 'HEAD', 'PATCH'], [41, 33, null]); ---- @@ -192,10 +197,10 @@ SELECT MAP([[1,2], [3,4]], ['a', 'b']); query error SELECT MAP() -query error DataFusion error: Execution error: map function requires 2 arguments, got 1 +query error DataFusion error: Error during planning: make_map requires an even number of arguments SELECT MAP(['POST', 'HEAD']) -query error DataFusion error: Execution error: Expected list, large_list or fixed_size_list, got Null +query error DataFusion error: Execution error: map key cannot be null SELECT MAP(null, [41, 33, 30]); query error DataFusion error: Execution error: map requires key and value lists to have the same length @@ -285,8 +290,12 @@ SELECT map(column8, column9) FROM t; {[4]: b} {[1, 2]: c} -query error +query ? SELECT map(column6, column7) FROM t; +---- +{[1, 2]: POST} +{[3]: PUT} +{[5]: NULL} query ? select Map {column6: column7} from t;