use of org.apache.beam.vendor.calcite.v1_28_0.org.apache.calcite.rel.core.Join in project calcite by apache.
the class JoinUnionTransposeRule method onMatch.
public void onMatch(RelOptRuleCall call) {
final Join join = call.rel(0);
final Union unionRel;
RelNode otherInput;
boolean unionOnLeft;
if (call.rel(1) instanceof Union) {
unionRel = call.rel(1);
otherInput = call.rel(2);
unionOnLeft = true;
} else {
otherInput = call.rel(1);
unionRel = call.rel(2);
unionOnLeft = false;
}
if (!unionRel.all) {
return;
}
if (!join.getVariablesSet().isEmpty()) {
return;
}
// in one or both branches of the union)
if (unionOnLeft) {
if (join.getJoinType().generatesNullsOnLeft()) {
return;
}
} else {
if (join.getJoinType().generatesNullsOnRight()) {
return;
}
}
List<RelNode> newUnionInputs = new ArrayList<RelNode>();
for (RelNode input : unionRel.getInputs()) {
RelNode joinLeft;
RelNode joinRight;
if (unionOnLeft) {
joinLeft = input;
joinRight = otherInput;
} else {
joinLeft = otherInput;
joinRight = input;
}
newUnionInputs.add(join.copy(join.getTraitSet(), join.getCondition(), joinLeft, joinRight, join.getJoinType(), join.isSemiJoinDone()));
}
final SetOp newUnionRel = unionRel.copy(unionRel.getTraitSet(), newUnionInputs, true);
call.transformTo(newUnionRel);
}
use of org.apache.beam.vendor.calcite.v1_28_0.org.apache.calcite.rel.core.Join in project calcite by apache.
the class LoptOptimizeJoinRule method pushDownFactor.
/**
* Creates a join tree where the new factor is pushed down one of the
* operands of the current join tree
*
* @param multiJoin join factors being optimized
* @param semiJoinOpt optimal semijoins for each factor
* @param joinTree current join tree
* @param factorToAdd new factor to be added
* @param factorsNeeded factors that must precede the factor to be added
* @param filtersToAdd filters remaining to be added; filters that are added
* to the join tree are removed from the list
* @param selfJoin true if the factor being added is part of a removable
* self-join
*
* @return optimal join tree with the new factor pushed down the current
* join tree if it is possible to do the pushdown; otherwise, null is
* returned
*/
private LoptJoinTree pushDownFactor(RelMetadataQuery mq, RelBuilder relBuilder, LoptMultiJoin multiJoin, LoptSemiJoinOptimizer semiJoinOpt, LoptJoinTree joinTree, int factorToAdd, BitSet factorsNeeded, List<RexNode> filtersToAdd, boolean selfJoin) {
// pushdown option only works if we already have a join tree
if (!isJoinTree(joinTree.getJoinTree())) {
return null;
}
int childNo = -1;
LoptJoinTree left = joinTree.getLeft();
LoptJoinTree right = joinTree.getRight();
Join joinRel = (Join) joinTree.getJoinTree();
JoinRelType joinType = joinRel.getJoinType();
// them, we need to keep the factors together
if (joinTree.isRemovableSelfJoin()) {
return null;
}
// half of the self-join.
if (selfJoin) {
BitSet selfJoinFactor = new BitSet(multiJoin.getNumJoinFactors());
selfJoinFactor.set(multiJoin.getOtherSelfJoinFactor(factorToAdd));
if (multiJoin.hasAllFactors(left, selfJoinFactor)) {
childNo = 0;
} else {
assert multiJoin.hasAllFactors(right, selfJoinFactor);
childNo = 1;
}
} else if ((factorsNeeded.cardinality() == 0) && !joinType.generatesNullsOnLeft()) {
childNo = 0;
} else {
// same check for RHS
if (multiJoin.hasAllFactors(left, factorsNeeded) && !joinType.generatesNullsOnLeft()) {
childNo = 0;
} else if (multiJoin.hasAllFactors(right, factorsNeeded) && !joinType.generatesNullsOnRight()) {
childNo = 1;
}
// if it couldn't be pushed down to either side, then it can
// only be put on top
}
if (childNo == -1) {
return null;
}
// remember the original join order before the pushdown so we can
// appropriately adjust any filters already attached to the join
// node
final List<Integer> origJoinOrder = joinTree.getTreeOrder();
// recursively pushdown the factor
LoptJoinTree subTree = (childNo == 0) ? left : right;
subTree = addFactorToTree(mq, relBuilder, multiJoin, semiJoinOpt, subTree, factorToAdd, factorsNeeded, filtersToAdd, selfJoin);
if (childNo == 0) {
left = subTree;
} else {
right = subTree;
}
// adjust the join condition from the original join tree to reflect
// pushdown of the new factor as well as any swapping that may have
// been done during the pushdown
RexNode newCondition = ((Join) joinTree.getJoinTree()).getCondition();
newCondition = adjustFilter(multiJoin, left, right, newCondition, factorToAdd, origJoinOrder, joinTree.getJoinTree().getRowType().getFieldList());
// join in createJoinSubtree
if ((joinType != JoinRelType.LEFT) && (joinType != JoinRelType.RIGHT)) {
RexNode condition = addFilters(multiJoin, left, -1, right, filtersToAdd, true);
RexBuilder rexBuilder = multiJoin.getMultiJoinRel().getCluster().getRexBuilder();
newCondition = RelOptUtil.andJoinFilters(rexBuilder, newCondition, condition);
}
// create the new join tree with the factor pushed down
return createJoinSubtree(mq, relBuilder, multiJoin, left, right, newCondition, joinType, filtersToAdd, false, false);
}
use of org.apache.beam.vendor.calcite.v1_28_0.org.apache.calcite.rel.core.Join in project calcite by apache.
the class JoinAddRedundantSemiJoinRule method onMatch.
// ~ Methods ----------------------------------------------------------------
public void onMatch(RelOptRuleCall call) {
Join origJoinRel = call.rel(0);
if (origJoinRel.isSemiJoinDone()) {
return;
}
// can't process outer joins using semijoins
if (origJoinRel.getJoinType() != JoinRelType.INNER) {
return;
}
// determine if we have a valid join condition
final JoinInfo joinInfo = origJoinRel.analyzeCondition();
if (joinInfo.leftKeys.size() == 0) {
return;
}
RelNode semiJoin = SemiJoin.create(origJoinRel.getLeft(), origJoinRel.getRight(), origJoinRel.getCondition(), joinInfo.leftKeys, joinInfo.rightKeys);
RelNode newJoinRel = origJoinRel.copy(origJoinRel.getTraitSet(), origJoinRel.getCondition(), semiJoin, origJoinRel.getRight(), JoinRelType.INNER, true);
call.transformTo(newJoinRel);
}
use of org.apache.beam.vendor.calcite.v1_28_0.org.apache.calcite.rel.core.Join in project calcite by apache.
the class JoinAssociateRule method onMatch.
// ~ Methods ----------------------------------------------------------------
public void onMatch(final RelOptRuleCall call) {
final Join topJoin = call.rel(0);
final Join bottomJoin = call.rel(1);
final RelNode relA = bottomJoin.getLeft();
final RelNode relB = bottomJoin.getRight();
final RelSubset relC = call.rel(2);
final RelOptCluster cluster = topJoin.getCluster();
final RexBuilder rexBuilder = cluster.getRexBuilder();
if (relC.getConvention() != relA.getConvention()) {
// EnumerableConvention, we're only interested in enumerable subsets.
return;
}
// topJoin
// / \
// bottomJoin C
// / \
// A B
final int aCount = relA.getRowType().getFieldCount();
final int bCount = relB.getRowType().getFieldCount();
final int cCount = relC.getRowType().getFieldCount();
final ImmutableBitSet aBitSet = ImmutableBitSet.range(0, aCount);
final ImmutableBitSet bBitSet = ImmutableBitSet.range(aCount, aCount + bCount);
if (!topJoin.getSystemFieldList().isEmpty()) {
// FIXME Enable this rule for joins with system fields
return;
}
// (Is this too strict?)
if (topJoin.getJoinType() != JoinRelType.INNER || bottomJoin.getJoinType() != JoinRelType.INNER) {
return;
}
// Goal is to transform to
//
// newTopJoin
// / \
// A newBottomJoin
// / \
// B C
// Split the condition of topJoin and bottomJoin into a conjunctions. A
// condition can be pushed down if it does not use columns from A.
final List<RexNode> top = Lists.newArrayList();
final List<RexNode> bottom = Lists.newArrayList();
JoinPushThroughJoinRule.split(topJoin.getCondition(), aBitSet, top, bottom);
JoinPushThroughJoinRule.split(bottomJoin.getCondition(), aBitSet, top, bottom);
// Mapping for moving conditions from topJoin or bottomJoin to
// newBottomJoin.
// target: | B | C |
// source: | A | B | C |
final Mappings.TargetMapping bottomMapping = Mappings.createShiftMapping(aCount + bCount + cCount, 0, aCount, bCount, bCount, aCount + bCount, cCount);
final List<RexNode> newBottomList = Lists.newArrayList();
new RexPermuteInputsShuttle(bottomMapping, relB, relC).visitList(bottom, newBottomList);
RexNode newBottomCondition = RexUtil.composeConjunction(rexBuilder, newBottomList, false);
final Join newBottomJoin = bottomJoin.copy(bottomJoin.getTraitSet(), newBottomCondition, relB, relC, JoinRelType.INNER, false);
// Condition for newTopJoin consists of pieces from bottomJoin and topJoin.
// Field ordinals do not need to be changed.
RexNode newTopCondition = RexUtil.composeConjunction(rexBuilder, top, false);
final Join newTopJoin = topJoin.copy(topJoin.getTraitSet(), newTopCondition, relA, newBottomJoin, JoinRelType.INNER, false);
call.transformTo(newTopJoin);
}
use of org.apache.beam.vendor.calcite.v1_28_0.org.apache.calcite.rel.core.Join in project calcite by apache.
the class JoinProjectTransposeRule method onMatch.
// ~ Methods ----------------------------------------------------------------
// implement RelOptRule
public void onMatch(RelOptRuleCall call) {
Join joinRel = call.rel(0);
JoinRelType joinType = joinRel.getJoinType();
Project leftProj;
Project rightProj;
RelNode leftJoinChild;
RelNode rightJoinChild;
// 2) input's projection doesn't generate nulls
if (hasLeftChild(call) && (includeOuter || !joinType.generatesNullsOnLeft())) {
leftProj = call.rel(1);
leftJoinChild = getProjectChild(call, leftProj, true);
} else {
leftProj = null;
leftJoinChild = call.rel(1);
}
if (hasRightChild(call) && (includeOuter || !joinType.generatesNullsOnRight())) {
rightProj = getRightChild(call);
rightJoinChild = getProjectChild(call, rightProj, false);
} else {
rightProj = null;
rightJoinChild = joinRel.getRight();
}
if ((leftProj == null) && (rightProj == null)) {
return;
}
// Construct two RexPrograms and combine them. The bottom program
// is a join of the projection expressions from the left and/or
// right projects that feed into the join. The top program contains
// the join condition.
// Create a row type representing a concatenation of the inputs
// underneath the projects that feed into the join. This is the input
// into the bottom RexProgram. Note that the join type is an inner
// join because the inputs haven't actually been joined yet.
RelDataType joinChildrenRowType = SqlValidatorUtil.deriveJoinRowType(leftJoinChild.getRowType(), rightJoinChild.getRowType(), JoinRelType.INNER, joinRel.getCluster().getTypeFactory(), null, Collections.<RelDataTypeField>emptyList());
// Create projection expressions, combining the projection expressions
// from the projects that feed into the join. For the RHS projection
// expressions, shift them to the right by the number of fields on
// the LHS. If the join input was not a projection, simply create
// references to the inputs.
int nProjExprs = joinRel.getRowType().getFieldCount();
final List<Pair<RexNode, String>> projects = new ArrayList<>();
final RexBuilder rexBuilder = joinRel.getCluster().getRexBuilder();
createProjectExprs(leftProj, leftJoinChild, 0, rexBuilder, joinChildrenRowType.getFieldList(), projects);
List<RelDataTypeField> leftFields = leftJoinChild.getRowType().getFieldList();
int nFieldsLeft = leftFields.size();
createProjectExprs(rightProj, rightJoinChild, nFieldsLeft, rexBuilder, joinChildrenRowType.getFieldList(), projects);
final List<RelDataType> projTypes = new ArrayList<>();
for (int i = 0; i < nProjExprs; i++) {
projTypes.add(projects.get(i).left.getType());
}
RelDataType projRowType = rexBuilder.getTypeFactory().createStructType(projTypes, Pair.right(projects));
// create the RexPrograms and merge them
RexProgram bottomProgram = RexProgram.create(joinChildrenRowType, Pair.left(projects), null, projRowType, rexBuilder);
RexProgramBuilder topProgramBuilder = new RexProgramBuilder(projRowType, rexBuilder);
topProgramBuilder.addIdentity();
topProgramBuilder.addCondition(joinRel.getCondition());
RexProgram topProgram = topProgramBuilder.getProgram();
RexProgram mergedProgram = RexProgramBuilder.mergePrograms(topProgram, bottomProgram, rexBuilder);
// expand out the join condition and construct a new LogicalJoin that
// directly references the join children without the intervening
// ProjectRels
RexNode newCondition = mergedProgram.expandLocalRef(mergedProgram.getCondition());
Join newJoinRel = joinRel.copy(joinRel.getTraitSet(), newCondition, leftJoinChild, rightJoinChild, joinRel.getJoinType(), joinRel.isSemiJoinDone());
// expand out the new projection expressions; if the join is an
// outer join, modify the expressions to reference the join output
final List<RexNode> newProjExprs = new ArrayList<>();
List<RexLocalRef> projList = mergedProgram.getProjectList();
List<RelDataTypeField> newJoinFields = newJoinRel.getRowType().getFieldList();
int nJoinFields = newJoinFields.size();
int[] adjustments = new int[nJoinFields];
for (int i = 0; i < nProjExprs; i++) {
RexNode newExpr = mergedProgram.expandLocalRef(projList.get(i));
if (joinType != JoinRelType.INNER) {
newExpr = newExpr.accept(new RelOptUtil.RexInputConverter(rexBuilder, joinChildrenRowType.getFieldList(), newJoinFields, adjustments));
}
newProjExprs.add(newExpr);
}
// finally, create the projection on top of the join
final RelBuilder relBuilder = call.builder();
relBuilder.push(newJoinRel);
relBuilder.project(newProjExprs, joinRel.getRowType().getFieldNames());
// projection to fix differences wrt nullability of fields
if (joinType != JoinRelType.INNER) {
relBuilder.convert(joinRel.getRowType(), false);
}
call.transformTo(relBuilder.build());
}
Aggregations