in src/query/src/main/java/org/apache/kylin/query/optrule/OlapFilterJoinRule.java [173:271]
protected void perform() {
List<RexNode> joinFilters = RelOptUtil.conjunctions(topJoinRel.getCondition());
// only match cross join and not-null filter
if (!joinFilters.isEmpty() || filterRel == null) {
return;
}
List<RexNode> aboveFilters = RelOptUtil.conjunctions(filterRel.getCondition());
// replace filters with pattern cast(col1 as ...) = col2 with col1 = col2
// to make such filters to be able to be pushed down to join conditions
aboveFilters = aboveFilters.stream().map(RexUtils::stripOffCastInColumnEqualPredicate)
.collect(Collectors.toList());
JoinRelType joinType = topJoinRel.getJoinType();
List<RexNode> leftFilters = new ArrayList<>();
List<RexNode> rightFilters = new ArrayList<>();
boolean filterPushed = pushDownFilter(aboveFilters, leftFilters, rightFilters, joinFilters);
// if nothing actually got pushed and there is nothing leftover, then this rule is a no-op
if ((!filterPushed && joinType == topJoinRel.getJoinType())
|| (joinFilters.isEmpty() && leftFilters.isEmpty() && rightFilters.isEmpty())) {
return;
}
// try transpose relNodes of joinRel to make as many relNodes be rewritten to inner join node as possible
boolean isNeedProject = false;
if (needTranspose && bottomJoin instanceof Join
&& RelOptUtil.conjunctions(((Join) bottomJoin).getCondition()).isEmpty() && joinFilters.size() > 1
&& !(relA instanceof Aggregate)) {
final int originFilterSize = joinFilters.size();
final Join originTopJoin = topJoinRel.copy(topJoinRel.getTraitSet(), topJoinRel.getInputs());
Filter newFilter = (Filter) transposeJoinRel();
// retry to push down new filters
List<RexNode> newLeftFilters = Lists.newArrayList();
List<RexNode> newRightFilters = Lists.newArrayList();
List<RexNode> newJoinFilters = Lists.newArrayList();
List<RexNode> newAboveFilter = RelOptUtil.conjunctions(newFilter.getCondition());
pushDownFilter(newAboveFilter, newLeftFilters, newRightFilters, newJoinFilters);
if (newJoinFilters.size() < originFilterSize) {
filterRel = newFilter;
leftFilters = newLeftFilters;
rightFilters = newRightFilters;
joinFilters = newJoinFilters;
aboveFilters = newAboveFilter;
isNeedProject = true;
} else {
topJoinRel = originTopJoin;
}
}
// create Filters on top of the children if any filters were pushed to them
final RexBuilder rexBuilder = topJoinRel.getCluster().getRexBuilder();
final RelNode leftRel = relBuilder.push(topJoinRel.getLeft()).filter(leftFilters).build();
final RelNode rightRel = relBuilder.push(topJoinRel.getRight()).filter(rightFilters).build();
// create the new join node referencing the new children and
// containing its new join filters (if there are any)
final ImmutableList<RelDataType> fieldTypes = ImmutableList.<RelDataType> builder()
.addAll(RelOptUtil.getFieldTypeList(leftRel.getRowType()))
.addAll(RelOptUtil.getFieldTypeList(rightRel.getRowType())).build();
final RexNode joinFilter = RexUtil.composeConjunction(rexBuilder,
RexUtil.fixUp(rexBuilder, joinFilters, fieldTypes), false);
// If nothing actually got pushed and there is nothing leftover,
// then this rule is a no-op
if (joinFilter.isAlwaysTrue() && leftFilters.isEmpty() && rightFilters.isEmpty()
&& joinType == topJoinRel.getJoinType()) {
return;
}
RelNode newJoinRel = topJoinRel.copy(topJoinRel.getTraitSet(), joinFilter, leftRel, rightRel, joinType,
topJoinRel.isSemiJoinDone());
call.getPlanner().onCopy(topJoinRel, newJoinRel);
if (!leftFilters.isEmpty()) {
call.getPlanner().onCopy(filterRel, leftRel);
}
if (!rightFilters.isEmpty()) {
call.getPlanner().onCopy(filterRel, rightRel);
}
relBuilder.push(newJoinRel);
// Create a project on top of the join if some of the columns have become
// NOT NULL due to the join-type getting stricter.
relBuilder.convert(topJoinRel.getRowType(), false);
// create a FilterRel on top of the join if needed
relBuilder.filter(RexUtil.fixUp(rexBuilder, aboveFilters,
RelOptUtil.getFieldTypeList(relBuilder.peek().getRowType())));
if (isNeedProject) {
final int aCount = relA.getRowType().getFieldCount();
final int bCount = relB.getRowType().getFieldCount();
final int cCount = relC.getRowType().getFieldCount();
final Mappings.TargetMapping originJoinFieldsToNew = Mappings.createShiftMapping(
aCount + bCount + cCount, 0, 0, cCount, cCount + aCount, cCount, bCount, cCount,
cCount + bCount, aCount);
relBuilder.project(relBuilder.fields(originJoinFieldsToNew));
}
call.transformTo(relBuilder.build());
}