use of org.apache.calcite.rel.core.Join in project calcite by apache.
the class JoinCommuteRule method swap.
/**
* Returns a relational expression with the inputs switched round. Does not
* modify <code>join</code>. Returns null if the join cannot be swapped (for
* example, because it is an outer join).
*
* @param join join to be swapped
* @param swapOuterJoins whether outer joins should be swapped
* @param relBuilder Builder for relational expressions
* @return swapped join if swapping possible; else null
*/
public static RelNode swap(Join join, boolean swapOuterJoins, RelBuilder relBuilder) {
final JoinRelType joinType = join.getJoinType();
if (!swapOuterJoins && joinType != JoinRelType.INNER) {
return null;
}
final RexBuilder rexBuilder = join.getCluster().getRexBuilder();
final RelDataType leftRowType = join.getLeft().getRowType();
final RelDataType rightRowType = join.getRight().getRowType();
final VariableReplacer variableReplacer = new VariableReplacer(rexBuilder, leftRowType, rightRowType);
final RexNode oldCondition = join.getCondition();
RexNode condition = variableReplacer.go(oldCondition);
// NOTE jvs 14-Mar-2006: We preserve attribute semiJoinDone after the
// swap. This way, we will generate one semijoin for the original
// join, and one for the swapped join, and no more. This
// doesn't prevent us from seeing any new combinations assuming
// that the planner tries the desired order (semijoins after swaps).
Join newJoin = join.copy(join.getTraitSet(), condition, join.getRight(), join.getLeft(), joinType.swap(), join.isSemiJoinDone());
final List<RexNode> exps = RelOptUtil.createSwappedJoinExprs(newJoin, join, true);
return relBuilder.push(newJoin).project(exps, join.getRowType().getFieldNames()).build();
}
use of org.apache.calcite.rel.core.Join in project calcite by apache.
the class JoinCommuteRule method onMatch.
public void onMatch(final RelOptRuleCall call) {
Join join = call.rel(0);
if (!join.getSystemFieldList().isEmpty()) {
// FIXME Enable this rule for joins with system fields
return;
}
final RelNode swapped = swap(join, this.swapOuter, call.builder());
if (swapped == null) {
return;
}
// The result is either a Project or, if the project is trivial, a
// raw Join.
final Join newJoin = swapped instanceof Join ? (Join) swapped : (Join) swapped.getInput(0);
call.transformTo(swapped);
// We have converted join='a join b' into swapped='select
// a0,a1,a2,b0,b1 from b join a'. Now register that project='select
// b0,b1,a0,a1,a2 from (select a0,a1,a2,b0,b1 from b join a)' is the
// same as 'b join a'. If we didn't do this, the swap join rule
// would fire on the new join, ad infinitum.
final RelBuilder relBuilder = call.builder();
final List<RexNode> exps = RelOptUtil.createSwappedJoinExprs(newJoin, join, false);
relBuilder.push(swapped).project(exps, newJoin.getRowType().getFieldNames());
call.getPlanner().ensureRegistered(relBuilder.build(), newJoin);
}
use of org.apache.calcite.rel.core.Join in project druid by druid-io.
the class DruidJoinRule method matches.
@Override
public boolean matches(RelOptRuleCall call) {
final Join join = call.rel(0);
final DruidRel<?> left = call.rel(1);
final DruidRel<?> right = call.rel(2);
// 3) Right has a PartialDruidQuery (i.e., is a real query, not top-level UNION ALL).
return canHandleCondition(join.getCondition(), join.getLeft().getRowType(), right) && left.getPartialDruidQuery() != null && right.getPartialDruidQuery() != null;
}
use of org.apache.calcite.rel.core.Join in project druid by druid-io.
the class FilterJoinExcludePushToChildRule method removeRedundantIsNotNullFilters.
/**
* This tries to find all the 'IS NOT NULL' filters in an inner join whose checking column is also
* a part of an equi-condition between the two tables. It removes such 'IS NOT NULL' filters from join since
* the equi-condition will never return true for null input, thus making the 'IS NOT NULL' filter a no-op.
* @param joinFilters
* @param joinType
* @param isSqlCompatible
*/
static void removeRedundantIsNotNullFilters(List<RexNode> joinFilters, JoinRelType joinType, boolean isSqlCompatible) {
if (joinType != JoinRelType.INNER || !isSqlCompatible) {
// only works for inner joins in SQL mode
return;
}
ImmutableList.Builder<RexNode> isNotNullFiltersBuilder = ImmutableList.builder();
ImmutableList.Builder<Pair<RexNode, RexNode>> equalityFiltersOperandBuilder = ImmutableList.builder();
joinFilters.stream().filter(joinFilter -> joinFilter instanceof RexCall).forEach(joinFilter -> {
if (joinFilter.isA(SqlKind.IS_NOT_NULL)) {
isNotNullFiltersBuilder.add(joinFilter);
} else if (joinFilter.isA(SqlKind.EQUALS)) {
List<RexNode> operands = ((RexCall) joinFilter).getOperands();
if (operands.size() == 2 && operands.stream().noneMatch(Objects::isNull)) {
equalityFiltersOperandBuilder.add(new Pair<>(operands.get(0), operands.get(1)));
}
}
});
List<Pair<RexNode, RexNode>> equalityFilters = equalityFiltersOperandBuilder.build();
ImmutableList.Builder<RexNode> removableFilters = ImmutableList.builder();
for (RexNode isNotNullFilter : isNotNullFiltersBuilder.build()) {
List<RexNode> operands = ((RexCall) isNotNullFilter).getOperands();
boolean canDrop = false;
for (Pair<RexNode, RexNode> equalityFilterOperands : equalityFilters) {
if ((equalityFilterOperands.lhs != null && equalityFilterOperands.lhs.equals(operands.get(0))) || (equalityFilterOperands.rhs != null && equalityFilterOperands.rhs.equals(operands.get(0)))) {
canDrop = true;
break;
}
}
if (canDrop) {
removableFilters.add(isNotNullFilter);
}
}
joinFilters.removeAll(removableFilters.build());
}
use of org.apache.calcite.rel.core.Join in project flink by apache.
the class RelDecorrelator method decorrelate.
protected RelNode decorrelate(RelNode root) {
// first adjust count() expression if any
final RelBuilderFactory f = relBuilderFactory();
HepProgram program = HepProgram.builder().addRuleInstance(AdjustProjectForCountAggregateRule.config(false, this, f).toRule()).addRuleInstance(AdjustProjectForCountAggregateRule.config(true, this, f).toRule()).addRuleInstance(FilterJoinRule.FilterIntoJoinRule.Config.DEFAULT.withRelBuilderFactory(f).withOperandSupplier(b0 -> b0.operand(Filter.class).oneInput(b1 -> b1.operand(Join.class).anyInputs())).withDescription("FilterJoinRule:filter").as(FilterJoinRule.FilterIntoJoinRule.Config.class).withSmart(true).withPredicate((join, joinType, exp) -> true).as(FilterJoinRule.FilterIntoJoinRule.Config.class).toRule()).addRuleInstance(CoreRules.FILTER_PROJECT_TRANSPOSE.config.withRelBuilderFactory(f).as(FilterProjectTransposeRule.Config.class).withOperandFor(Filter.class, filter -> !RexUtil.containsCorrelation(filter.getCondition()), Project.class, project -> true).withCopyFilter(true).withCopyProject(true).toRule()).addRuleInstance(FilterCorrelateRule.Config.DEFAULT.withRelBuilderFactory(f).toRule()).build();
HepPlanner planner = createPlanner(program);
planner.setRoot(root);
root = planner.findBestExp();
// Perform decorrelation.
map.clear();
final Frame frame = getInvoke(root, null);
if (frame != null) {
// has been rewritten; apply rules post-decorrelation
final HepProgram program2 = HepProgram.builder().addRuleInstance(CoreRules.FILTER_INTO_JOIN.config.withRelBuilderFactory(f).toRule()).addRuleInstance(CoreRules.JOIN_CONDITION_PUSH.config.withRelBuilderFactory(f).toRule()).build();
final HepPlanner planner2 = createPlanner(program2);
final RelNode newRoot = frame.r;
planner2.setRoot(newRoot);
return planner2.findBestExp();
}
return root;
}
Aggregations