Skip to content

Commit f8918e7

Browse files
committed
refactor(cubesql): Rewrite join on __cubeJoinField directly to CubeScan, without CrossJoin
1 parent 8d1080b commit f8918e7

File tree

1 file changed

+82
-44
lines changed
  • rust/cubesql/cubesql/src/compile/rewrite/rules

1 file changed

+82
-44
lines changed

rust/cubesql/cubesql/src/compile/rewrite/rules/members.rs

Lines changed: 82 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)