@@ -336,66 +336,71 @@ impl RewriteRules for MemberRules {
336336 "?left_members" ,
337337 "?right_members" ,
338338 ) ,
339+ // It is incorrect to merge two CubeScan's into one after grouping
340+ // __cubeJoinField is a representation of join from data model,
341+ // and it is valid only for ungrouped queries to data source
342+ // So CubeScanCanPushdownJoin and CubeScanUngrouped are fixed to true
343+ // Limit and offset are not allowed
344+ // Consider plan like Join(CubeScan(limit = 1), CubeScan(limit = 1))
345+ // Join would check only one row from left scan and only one from right
346+ // And if they mismatch it will produce empty table
347+ // There's no way to represent this as a single CubeScan
348+ // Join does not guarantee ordering, so there's no point in keeping orders in RHS
339349 transforming_rewrite(
340- "join-to-cross -join" ,
350+ "push-down-cube -join" ,
341351 join(
342352 cube_scan(
343353 "?left_alias_to_cube" ,
344354 "?left_members" ,
345355 "?left_filters" ,
346356 "?left_orders" ,
347- "?left_limit " ,
348- "?left_offset " ,
357+ "CubeScanLimit:None " ,
358+ "CubeScanOffset:None " ,
349359 "?left_split" ,
350- "?left_can_pushdown_join " ,
360+ "CubeScanCanPushdownJoin:true " ,
351361 "CubeScanWrapped:false" ,
352- "?left_ungrouped " ,
362+ "CubeScanUngrouped:true " ,
353363 ) ,
354364 cube_scan(
355365 "?right_alias_to_cube" ,
356366 "?right_members" ,
357367 "?right_filters" ,
358368 "?right_orders" ,
359- "?right_limit " ,
360- "?right_offset " ,
369+ "CubeScanLimit:None " ,
370+ "CubeScanOffset:None " ,
361371 "?right_split" ,
362- "?right_can_pushdown_join " ,
372+ "CubeScanCanPushdownJoin:true " ,
363373 "CubeScanWrapped:false" ,
364- "?right_ungrouped " ,
374+ "CubeScanUngrouped:true " ,
365375 ) ,
366376 "?left_on" ,
367377 "?right_on" ,
368378 "?join_type" ,
369379 "?join_constraint" ,
370380 "?null_equals_null" ,
371381 ) ,
372- cross_join(
373- cube_scan(
374- "?left_alias_to_cube" ,
375- "?left_members" ,
376- "?left_filters" ,
377- "?left_orders" ,
378- "?left_limit" ,
379- "?left_offset" ,
380- "?left_split" ,
381- "?left_can_pushdown_join" ,
382- "CubeScanWrapped:false" ,
383- "?left_ungrouped" ,
384- ) ,
385- cube_scan(
386- "?right_alias_to_cube" ,
387- "?right_members" ,
388- "?right_filters" ,
389- "?right_orders" ,
390- "?right_limit" ,
391- "?right_offset" ,
392- "?right_split" ,
393- "?right_can_pushdown_join" ,
394- "CubeScanWrapped:false" ,
395- "?right_ungrouped" ,
396- ) ,
382+ cube_scan(
383+ "?out_alias_to_cube" ,
384+ cube_scan_members( "?left_members" , "?right_members" ) ,
385+ cube_scan_filters( "?left_filters" , "?right_filters" ) ,
386+ cube_scan_order_empty_tail( ) ,
387+ "CubeScanLimit:None" ,
388+ "CubeScanOffset:None" ,
389+ // New CubeScan is treated as "not yet split", to give split rules one more chance
390+ "CubeScanSplit:false" ,
391+ "CubeScanCanPushdownJoin:true" ,
392+ "CubeScanWrapped:false" ,
393+ "CubeScanUngrouped:true" ,
394+ ) ,
395+ self . push_down_cube_join(
396+ "?left_alias_to_cube" ,
397+ "?right_alias_to_cube" ,
398+ "?out_alias_to_cube" ,
399+ "?left_members" ,
400+ "?right_members" ,
401+ "?left_on" ,
402+ "?right_on" ,
397403 ) ,
398- self . join_to_cross_join( "?left_on" , "?right_on" , "?left_members" , "?right_members" ) ,
399404 ) ,
400405 ] ;
401406
@@ -2620,26 +2625,59 @@ impl MemberRules {
26202625 }
26212626 }
26222627
2623- fn join_to_cross_join (
2628+ fn push_down_cube_join (
26242629 & self ,
2630+ left_alias_to_cube_var : & ' static str ,
2631+ right_alias_to_cube_var : & ' static str ,
2632+ out_alias_to_cube_var : & ' static str ,
2633+ left_members_var : & ' static str ,
2634+ right_members_var : & ' static str ,
26252635 left_on_var : & ' static str ,
26262636 right_on_var : & ' static str ,
2627- left_aliases_var : & ' static str ,
2628- right_aliases_var : & ' static str ,
26292637 ) -> impl Fn ( & mut CubeEGraph , & mut Subst ) -> bool {
2638+ let left_alias_to_cube_var = var ! ( left_alias_to_cube_var) ;
2639+ let right_alias_to_cube_var = var ! ( right_alias_to_cube_var) ;
2640+ let out_alias_to_cube_var = var ! ( out_alias_to_cube_var) ;
2641+ let left_members_var = var ! ( left_members_var) ;
2642+ let right_members_var = var ! ( right_members_var) ;
26302643 let left_on_var = var ! ( left_on_var) ;
26312644 let right_on_var = var ! ( right_on_var) ;
2632- let left_aliases_var = var ! ( left_aliases_var) ;
2633- let right_aliases_var = var ! ( right_aliases_var) ;
26342645 move |egraph, subst| {
2635- is_proper_cube_join_condition (
2646+ if ! is_proper_cube_join_condition (
26362647 egraph,
26372648 subst,
2638- left_aliases_var ,
2649+ left_members_var ,
26392650 left_on_var,
2640- right_aliases_var ,
2651+ right_members_var ,
26412652 right_on_var,
2642- )
2653+ ) {
2654+ return false ;
2655+ }
2656+
2657+ for left_alias_to_cube in
2658+ var_iter ! ( egraph[ subst[ left_alias_to_cube_var] ] , CubeScanAliasToCube )
2659+ {
2660+ for right_alias_to_cube in
2661+ var_iter ! ( egraph[ subst[ right_alias_to_cube_var] ] , CubeScanAliasToCube )
2662+ {
2663+ subst. insert (
2664+ out_alias_to_cube_var,
2665+ egraph. add ( LogicalPlanLanguage :: CubeScanAliasToCube (
2666+ CubeScanAliasToCube (
2667+ left_alias_to_cube
2668+ . iter ( )
2669+ . chain ( right_alias_to_cube. iter ( ) )
2670+ . cloned ( )
2671+ . collect ( ) ,
2672+ ) ,
2673+ ) ) ,
2674+ ) ;
2675+
2676+ return true ;
2677+ }
2678+ }
2679+
2680+ false
26432681 }
26442682 }
26452683
0 commit comments