@Override
public void onMatch(RelOptRuleCall call) {
final ProjectRelBase project = call.rel(0);
final JoinRelBase join = call.rel(1);
final RelNode left = call.rel(2);
final AggregateRelBase aggregate = call.rel(3);
final BitSet bits = RelOptUtil.InputFinder.bits(project.getProjects(),
null);
final BitSet rightBits = BitSets.range(left.getRowType().getFieldCount(),
join.getRowType().getFieldCount());
if (bits.intersects(rightBits)) {
return;
}
final JoinInfo joinInfo = join.analyzeCondition();
if (!joinInfo.rightSet().equals(BitSets.range(aggregate.getGroupCount()))) {
// Rule requires that aggregate key to be the same as the join key.
// By the way, neither a super-set nor a sub-set would work.
return;
}
final List<Integer> newRightKeys = Lists.newArrayList();
final IntList aggregateKeys = BitSets.toList(aggregate.getGroupSet());
for (int key : joinInfo.rightKeys) {
newRightKeys.add(aggregateKeys.get(key));
}
final SemiJoinRel semiJoin =
new SemiJoinRel(join.getCluster(),
join.getCluster().traitSetOf(Convention.NONE),
left, aggregate.getChild(),
join.getCondition(), joinInfo.leftKeys,
ImmutableIntList.copyOf(newRightKeys));
final ProjectRelBase newProject =
project.copy(project.getTraitSet(), semiJoin, project.getProjects(),
project.getRowType());