@@ -19,9 +19,9 @@ use insta::assert_snapshot;
1919use std:: sync:: Arc ;
2020
2121use crate :: physical_optimizer:: test_utils:: {
22- bounded_window_exec, global_limit_exec, local_limit_exec , memory_exec ,
23- projection_exec, repartition_exec, sort_exec, sort_expr, sort_expr_options ,
24- sort_merge_join_exec, sort_preserving_merge_exec, union_exec,
22+ bounded_window_exec, global_limit_exec, hash_join_exec , local_limit_exec ,
23+ memory_exec , projection_exec, repartition_exec, sort_exec, sort_expr,
24+ sort_expr_options , sort_merge_join_exec, sort_preserving_merge_exec, union_exec,
2525} ;
2626
2727use arrow:: compute:: SortOptions ;
@@ -30,8 +30,8 @@ use datafusion::datasource::stream::{FileStreamProvider, StreamConfig, StreamTab
3030use datafusion:: prelude:: { CsvReadOptions , SessionContext } ;
3131use datafusion_common:: config:: ConfigOptions ;
3232use datafusion_common:: { JoinType , Result , ScalarValue } ;
33- use datafusion_physical_expr:: Partitioning ;
3433use datafusion_physical_expr:: expressions:: { Literal , col} ;
34+ use datafusion_physical_expr:: { Partitioning , RangePartitioning , SplitPoint } ;
3535use datafusion_physical_expr_common:: sort_expr:: LexOrdering ;
3636use datafusion_physical_optimizer:: PhysicalOptimizerRule ;
3737use datafusion_physical_optimizer:: sanity_checker:: SanityCheckPlan ;
@@ -400,6 +400,49 @@ fn assert_sanity_check(plan: &Arc<dyn ExecutionPlan>, is_sane: bool) {
400400 ) ;
401401}
402402
403+ fn range_partitioned_exec (
404+ schema : & SchemaRef ,
405+ key : & str ,
406+ split_points : impl IntoIterator < Item = i32 > ,
407+ ) -> Result < Arc < dyn ExecutionPlan > > {
408+ let split_points = split_points
409+ . into_iter ( )
410+ . map ( |value| SplitPoint :: new ( vec ! [ ScalarValue :: Int32 ( Some ( value) ) ] ) )
411+ . collect ( ) ;
412+ let partitioning = Partitioning :: Range ( RangePartitioning :: try_new (
413+ [ sort_expr ( key, schema) ] . into ( ) ,
414+ split_points,
415+ ) ?) ;
416+ RepartitionExec :: try_new ( memory_exec ( schema) , partitioning)
417+ . map ( |exec| Arc :: new ( exec) as Arc < dyn ExecutionPlan > )
418+ }
419+
420+ #[ test]
421+ fn test_partitioned_hash_join_requires_co_partitioned_children ( ) -> Result < ( ) > {
422+ let schema = create_test_schema2 ( ) ;
423+ let join_on = vec ! [ ( col( "a" , & schema) ?, col( "a" , & schema) ?) ] ;
424+
425+ let compatible_join = hash_join_exec (
426+ range_partitioned_exec ( & schema, "a" , [ 10 ] ) ?,
427+ range_partitioned_exec ( & schema, "a" , [ 10 ] ) ?,
428+ join_on. clone ( ) ,
429+ None ,
430+ & JoinType :: Inner ,
431+ ) ?;
432+ assert_sanity_check ( & compatible_join, true ) ;
433+
434+ let incompatible_join = hash_join_exec (
435+ range_partitioned_exec ( & schema, "a" , [ 10 ] ) ?,
436+ range_partitioned_exec ( & schema, "a" , [ 20 ] ) ?,
437+ join_on,
438+ None ,
439+ & JoinType :: Inner ,
440+ ) ?;
441+ assert_sanity_check ( & incompatible_join, false ) ;
442+
443+ Ok ( ( ) )
444+ }
445+
403446#[ tokio:: test]
404447/// Tests that plan is valid when the sort requirements are satisfied.
405448async fn test_bounded_window_agg_sort_requirement ( ) -> Result < ( ) > {
0 commit comments