@@ -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,50 @@ 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( "b" , & schema) ?) ] ;
424+ let right = range_partitioned_exec ( & schema, "b" , [ 10 ] ) ?;
425+
426+ let valid_join = hash_join_exec (
427+ range_partitioned_exec ( & schema, "a" , [ 10 ] ) ?,
428+ Arc :: clone ( & right) ,
429+ join_on. clone ( ) ,
430+ None ,
431+ & JoinType :: Inner ,
432+ ) ?;
433+ assert_sanity_check ( & valid_join, true ) ;
434+
435+ let invalid_join = hash_join_exec (
436+ range_partitioned_exec ( & schema, "a" , [ 20 ] ) ?,
437+ right,
438+ join_on,
439+ None ,
440+ & JoinType :: Inner ,
441+ ) ?;
442+ assert_sanity_check ( & invalid_join, false ) ;
443+
444+ Ok ( ( ) )
445+ }
446+
403447#[ tokio:: test]
404448/// Tests that plan is valid when the sort requirements are satisfied.
405449async fn test_bounded_window_agg_sort_requirement ( ) -> Result < ( ) > {
0 commit comments