public boolean matches(RelOptRuleCall call) { JoinRel join = (JoinRel) call.rels[0]; switch (join.getJoinType()) { case INNER: case LEFT: return true; case FULL: case RIGHT: return false; default: throw Util.unexpected(join.getJoinType()); } }
/** * Combines the join filters from the left and right inputs (if they are MultiJoinRels) with the * join filter in the joinrel into a single AND'd join filter, unless the inputs correspond to * null generating inputs in an outer join * * @param joinRel join rel * @param left left child of the joinrel * @param right right child of the joinrel * @return combined join filters AND'd together */ private RexNode combineJoinFilters(JoinRel joinRel, RelNode left, RelNode right) { RexBuilder rexBuilder = joinRel.getCluster().getRexBuilder(); JoinRelType joinType = joinRel.getJoinType(); // first need to adjust the RexInputs of the right child, since // those need to shift over to the right RexNode rightFilter = null; if (canCombine(right, joinType.generatesNullsOnRight())) { MultiJoinRel multiJoin = (MultiJoinRel) right; rightFilter = shiftRightFilter(joinRel, left, multiJoin, multiJoin.getJoinFilter()); } // AND the join condition if this isn't a left or right outer join; // in those cases, the outer join condition is already tracked // separately RexNode newFilter = null; if ((joinType != JoinRelType.LEFT) && (joinType != JoinRelType.RIGHT)) { newFilter = joinRel.getCondition(); } if (canCombine(left, joinType.generatesNullsOnLeft())) { RexNode leftFilter = ((MultiJoinRel) left).getJoinFilter(); newFilter = RelOptUtil.andJoinFilters(rexBuilder, newFilter, leftFilter); } newFilter = RelOptUtil.andJoinFilters(rexBuilder, newFilter, rightFilter); return newFilter; }
/** * Combines the outer join conditions and join types from the left and right join inputs. If the * join itself is either a left or right outer join, then the join condition corresponding to the * join is also set in the position corresponding to the null-generating input into the join. The * join type is also set. * * @param joinRel join rel * @param combinedInputs the combined inputs to the join * @param left left child of the joinrel * @param right right child of the joinrel * @param combinedConds the array containing the combined join conditions * @param joinTypes the array containing the combined join types * @return combined join filters AND'd together */ private RexNode[] combineOuterJoins( JoinRel joinRel, RelNode[] combinedInputs, RelNode left, RelNode right, RexNode[] combinedConds, JoinRelType[] joinTypes) { JoinRelType joinType = joinRel.getJoinType(); int nCombinedInputs = combinedInputs.length; boolean leftCombined = canCombine(left, joinType.generatesNullsOnLeft()); boolean rightCombined = canCombine(right, joinType.generatesNullsOnRight()); if (joinType == JoinRelType.LEFT) { if (leftCombined) { copyOuterJoinInfo((MultiJoinRel) left, combinedConds, joinTypes, 0, 0, null, null); } else { joinTypes[0] = JoinRelType.INNER; } combinedConds[nCombinedInputs - 1] = joinRel.getCondition(); joinTypes[nCombinedInputs - 1] = joinType; } else if (joinType == JoinRelType.RIGHT) { if (rightCombined) { copyOuterJoinInfo( (MultiJoinRel) right, combinedConds, joinTypes, 1, left.getRowType().getFieldCount(), right.getRowType().getFields(), joinRel.getRowType().getFields()); } else { joinTypes[nCombinedInputs - 1] = JoinRelType.INNER; } combinedConds[0] = joinRel.getCondition(); joinTypes[0] = joinType; } else { int nInputsLeft; if (leftCombined) { nInputsLeft = left.getInputs().length; copyOuterJoinInfo((MultiJoinRel) left, combinedConds, joinTypes, 0, 0, null, null); } else { nInputsLeft = 1; joinTypes[0] = JoinRelType.INNER; } if (rightCombined) { copyOuterJoinInfo( (MultiJoinRel) right, combinedConds, joinTypes, nInputsLeft, left.getRowType().getFieldCount(), right.getRowType().getFields(), joinRel.getRowType().getFields()); } else { joinTypes[nInputsLeft] = JoinRelType.INNER; } } return combinedConds; }
/** * Combines the inputs into a JoinRel into an array of inputs. * * @param join original join * @param left left input into join * @param right right input into join * @param projFieldsList returns a list of the new combined projection fields * @param joinFieldRefCountsList returns a list of the new combined join field reference counts * @return combined left and right inputs in an array */ private RelNode[] combineInputs( JoinRel join, RelNode left, RelNode right, List<BitSet> projFieldsList, List<int[]> joinFieldRefCountsList) { // leave the null generating sides of an outer join intact; don't // pull up those children inputs into the array we're constructing int nInputs; int nInputsOnLeft; MultiJoinRel leftMultiJoin = null; JoinRelType joinType = join.getJoinType(); boolean combineLeft = canCombine(left, joinType.generatesNullsOnLeft()); if (combineLeft) { leftMultiJoin = (MultiJoinRel) left; nInputs = left.getInputs().length; nInputsOnLeft = nInputs; } else { nInputs = 1; nInputsOnLeft = 1; } MultiJoinRel rightMultiJoin = null; boolean combineRight = canCombine(right, joinType.generatesNullsOnRight()); if (combineRight) { rightMultiJoin = (MultiJoinRel) right; nInputs += right.getInputs().length; } else { nInputs += 1; } RelNode[] newInputs = new RelNode[nInputs]; int i = 0; if (combineLeft) { for (; i < left.getInputs().length; i++) { newInputs[i] = leftMultiJoin.getInput(i); projFieldsList.add(((MultiJoinRel) left).getProjFields()[i]); joinFieldRefCountsList.add(((MultiJoinRel) left).getJoinFieldRefCountsMap().get(i)); } } else { newInputs[0] = left; i = 1; projFieldsList.add(null); joinFieldRefCountsList.add(new int[left.getRowType().getFieldCount()]); } if (combineRight) { for (; i < nInputs; i++) { newInputs[i] = rightMultiJoin.getInput(i - nInputsOnLeft); projFieldsList.add(((MultiJoinRel) right).getProjFields()[i - nInputsOnLeft]); joinFieldRefCountsList.add( ((MultiJoinRel) right).getJoinFieldRefCountsMap().get(i - nInputsOnLeft)); } } else { newInputs[i] = right; projFieldsList.add(null); joinFieldRefCountsList.add(new int[right.getRowType().getFieldCount()]); } return newInputs; }
public void onMatch(RelOptRuleCall call) { JoinRel origJoinRel = (JoinRel) call.rels[0]; RelNode left = call.rels[1]; RelNode right = call.rels[2]; // combine the children MultiJoinRel inputs into an array of inputs // for the new MultiJoinRel List<BitSet> projFieldsList = new ArrayList<BitSet>(); List<int[]> joinFieldRefCountsList = new ArrayList<int[]>(); RelNode[] newInputs = combineInputs(origJoinRel, left, right, projFieldsList, joinFieldRefCountsList); // combine the outer join information from the left and right // inputs, and include the outer join information from the current // join, if it's a left/right outer join RexNode[] newOuterJoinConds = new RexNode[newInputs.length]; JoinRelType[] joinTypes = new JoinRelType[newInputs.length]; combineOuterJoins(origJoinRel, newInputs, left, right, newOuterJoinConds, joinTypes); // pull up the join filters from the children MultiJoinRels and // combine them with the join filter associated with this JoinRel to // form the join filter for the new MultiJoinRel RexNode newJoinFilter = combineJoinFilters(origJoinRel, left, right); // add on the join field reference counts for the join condition // associated with this JoinRel Map<Integer, int[]> newJoinFieldRefCountsMap = new HashMap<Integer, int[]>(); addOnJoinFieldRefCounts( newInputs, origJoinRel.getRowType().getFieldCount(), origJoinRel.getCondition(), joinFieldRefCountsList, newJoinFieldRefCountsMap); RexNode newPostJoinFilter = combinePostJoinFilters(origJoinRel, left, right); RelNode multiJoin = new MultiJoinRel( origJoinRel.getCluster(), newInputs, newJoinFilter, origJoinRel.getRowType(), (origJoinRel.getJoinType() == JoinRelType.FULL), newOuterJoinConds, joinTypes, projFieldsList.toArray(new BitSet[projFieldsList.size()]), newJoinFieldRefCountsMap, newPostJoinFilter); call.transformTo(multiJoin); }
// implement RelOptRule public void onMatch(RelOptRuleCall call) { ProjectRel origProj = call.rel(0); JoinRel joinRel = call.rel(1); // locate all fields referenced in the projection and join condition; // determine which inputs are referenced in the projection and // join condition; if all fields are being referenced and there are no // special expressions, no point in proceeding any further PushProjector pushProject = new PushProjector(origProj, joinRel.getCondition(), joinRel, preserveExprCondition); if (pushProject.locateAllRefs()) { return; } // create left and right projections, projecting only those // fields referenced on each side RelNode leftProjRel = pushProject.createProjectRefsAndExprs(joinRel.getLeft(), true, false); RelNode rightProjRel = pushProject.createProjectRefsAndExprs(joinRel.getRight(), true, true); // convert the join condition to reference the projected columns RexNode newJoinFilter = null; int[] adjustments = pushProject.getAdjustments(); if (joinRel.getCondition() != null) { List<RelDataTypeField> projJoinFieldList = new ArrayList<RelDataTypeField>(); projJoinFieldList.addAll(joinRel.getSystemFieldList()); projJoinFieldList.addAll(leftProjRel.getRowType().getFieldList()); projJoinFieldList.addAll(rightProjRel.getRowType().getFieldList()); newJoinFilter = pushProject.convertRefsAndExprs(joinRel.getCondition(), projJoinFieldList, adjustments); } // create a new joinrel with the projected children JoinRel newJoinRel = new JoinRel( joinRel.getCluster(), leftProjRel, rightProjRel, newJoinFilter, joinRel.getJoinType(), Collections.<String>emptySet(), joinRel.isSemiJoinDone(), joinRel.getSystemFieldList()); // put the original project on top of the join, converting it to // reference the modified projection list ProjectRel topProject = pushProject.createNewProject(newJoinRel, adjustments); call.transformTo(topProject); }
public void onMatch(RelOptRuleCall call) { assert matches(call); final JoinRel join = (JoinRel) call.rels[0]; final List<Integer> leftKeys = new ArrayList<Integer>(); final List<Integer> rightKeys = new ArrayList<Integer>(); RelNode right = join.getRight(); final RelNode left = join.getLeft(); RexNode remainingCondition = RelOptUtil.splitJoinCondition(left, right, join.getCondition(), leftKeys, rightKeys); assert leftKeys.size() == rightKeys.size(); final List<CorrelatorRel.Correlation> correlationList = new ArrayList<CorrelatorRel.Correlation>(); if (leftKeys.size() > 0) { final RelOptCluster cluster = join.getCluster(); final RexBuilder rexBuilder = cluster.getRexBuilder(); int k = 0; RexNode condition = null; for (Integer leftKey : leftKeys) { Integer rightKey = rightKeys.get(k++); final String dyn_inIdStr = cluster.getQuery().createCorrel(); final int dyn_inId = RelOptQuery.getCorrelOrdinal(dyn_inIdStr); // Create correlation to say 'each row, set variable #id // to the value of column #leftKey'. correlationList.add(new CorrelatorRel.Correlation(dyn_inId, leftKey)); condition = RelOptUtil.andJoinFilters( rexBuilder, condition, rexBuilder.makeCall( SqlStdOperatorTable.equalsOperator, rexBuilder.makeInputRef( right.getRowType().getFieldList().get(rightKey).getType(), rightKey), rexBuilder.makeCorrel( left.getRowType().getFieldList().get(leftKey).getType(), dyn_inIdStr))); } right = CalcRel.createFilter(right, condition); } RelNode newRel = new CorrelatorRel( join.getCluster(), left, right, remainingCondition, correlationList, join.getJoinType()); call.transformTo(newRel); }
public void onMatch(RelOptRuleCall call) { JoinRel join = (JoinRel) call.rels[0]; List<RexNode> expList = new ArrayList<RexNode>(Arrays.asList(join.getChildExps())); if (reduceExpressions(join, expList)) { call.transformTo( new JoinRel( join.getCluster(), join.getLeft(), join.getRight(), expList.get(0), join.getJoinType(), join.getVariablesStopped())); // New plan is absolutely better than old plan. call.getPlanner().setImportance(join, 0.0); } }