use of org.apache.beam.vendor.calcite.v1_28_0.org.apache.calcite.util.Pair in project calcite by apache.
the class JoinToMultiJoinRule method onMatch.
// ~ Methods ----------------------------------------------------------------
public void onMatch(RelOptRuleCall call) {
final Join origJoin = call.rel(0);
final RelNode left = call.rel(1);
final RelNode right = call.rel(2);
// combine the children MultiJoin inputs into an array of inputs
// for the new MultiJoin
final List<ImmutableBitSet> projFieldsList = Lists.newArrayList();
final List<int[]> joinFieldRefCountsList = Lists.newArrayList();
final List<RelNode> newInputs = combineInputs(origJoin, 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
final List<Pair<JoinRelType, RexNode>> joinSpecs = Lists.newArrayList();
combineOuterJoins(origJoin, newInputs, left, right, joinSpecs);
// pull up the join filters from the children MultiJoinRels and
// combine them with the join filter associated with this LogicalJoin to
// form the join filter for the new MultiJoin
List<RexNode> newJoinFilters = combineJoinFilters(origJoin, left, right);
// add on the join field reference counts for the join condition
// associated with this LogicalJoin
final ImmutableMap<Integer, ImmutableIntList> newJoinFieldRefCountsMap = addOnJoinFieldRefCounts(newInputs, origJoin.getRowType().getFieldCount(), origJoin.getCondition(), joinFieldRefCountsList);
List<RexNode> newPostJoinFilters = combinePostJoinFilters(origJoin, left, right);
final RexBuilder rexBuilder = origJoin.getCluster().getRexBuilder();
RelNode multiJoin = new MultiJoin(origJoin.getCluster(), newInputs, RexUtil.composeConjunction(rexBuilder, newJoinFilters, false), origJoin.getRowType(), origJoin.getJoinType() == JoinRelType.FULL, Pair.right(joinSpecs), Pair.left(joinSpecs), projFieldsList, newJoinFieldRefCountsMap, RexUtil.composeConjunction(rexBuilder, newPostJoinFilters, true));
call.transformTo(multiJoin);
}
use of org.apache.beam.vendor.calcite.v1_28_0.org.apache.calcite.util.Pair in project calcite by apache.
the class LoptOptimizeJoinRule method createReplacementJoin.
/**
* Creates a replacement join, projecting either dummy columns or
* replacement keys from the factor that doesn't actually need to be joined.
*
* @param multiJoin join factors being optimized
* @param semiJoinOpt optimal semijoins for each factor
* @param currJoinTree current join tree being added to
* @param leftIdx if ≥ 0, when creating the replacement join, only consider
* filters that reference leftIdx in currJoinTree; otherwise, consider all
* filters that reference any factor in currJoinTree
* @param factorToAdd new factor whose join can be removed
* @param newKeys join keys that need to be replaced
* @param replacementKeys the keys that replace the join keys; null if we're
* removing the null generating factor in an outer join
* @param filtersToAdd filters remaining to be added; filters added to the
* new join tree are removed from the list
*
* @return created join tree with an appropriate projection for the factor
* that can be removed
*/
private LoptJoinTree createReplacementJoin(RelBuilder relBuilder, LoptMultiJoin multiJoin, LoptSemiJoinOptimizer semiJoinOpt, LoptJoinTree currJoinTree, int leftIdx, int factorToAdd, ImmutableIntList newKeys, Integer[] replacementKeys, List<RexNode> filtersToAdd) {
// create a projection, projecting the fields from the join tree
// containing the current joinRel and the new factor; for fields
// corresponding to join keys, replace them with the corresponding key
// from the replacementKeys passed in; for other fields, just create a
// null expression as a placeholder for the column; this is done so we
// don't have to adjust the offsets of other expressions that reference
// the new factor; the placeholder expression values should never be
// referenced, so that's why it's ok to create these possibly invalid
// expressions
RelNode currJoinRel = currJoinTree.getJoinTree();
List<RelDataTypeField> currFields = currJoinRel.getRowType().getFieldList();
final int nCurrFields = currFields.size();
List<RelDataTypeField> newFields = multiJoin.getJoinFactor(factorToAdd).getRowType().getFieldList();
final int nNewFields = newFields.size();
List<Pair<RexNode, String>> projects = Lists.newArrayList();
RexBuilder rexBuilder = currJoinRel.getCluster().getRexBuilder();
RelDataTypeFactory typeFactory = rexBuilder.getTypeFactory();
for (int i = 0; i < nCurrFields; i++) {
projects.add(Pair.of((RexNode) rexBuilder.makeInputRef(currFields.get(i).getType(), i), currFields.get(i).getName()));
}
for (int i = 0; i < nNewFields; i++) {
RexNode projExpr;
RelDataType newType = newFields.get(i).getType();
if (!newKeys.contains(i)) {
if (replacementKeys == null) {
// null generating factor in an outer join; so make the
// type nullable
newType = typeFactory.createTypeWithNullability(newType, true);
}
projExpr = rexBuilder.makeCast(newType, rexBuilder.constantNull());
} else {
RelDataTypeField mappedField = currFields.get(replacementKeys[i]);
RexNode mappedInput = rexBuilder.makeInputRef(mappedField.getType(), replacementKeys[i]);
// if the types aren't the same, create a cast
if (mappedField.getType() == newType) {
projExpr = mappedInput;
} else {
projExpr = rexBuilder.makeCast(newFields.get(i).getType(), mappedInput);
}
}
projects.add(Pair.of(projExpr, newFields.get(i).getName()));
}
relBuilder.push(currJoinRel);
relBuilder.project(Pair.left(projects), Pair.right(projects));
// remove the join conditions corresponding to the join we're removing;
// we don't actually need to use them, but we need to remove them
// from the list since they're no longer needed
LoptJoinTree newTree = new LoptJoinTree(semiJoinOpt.getChosenSemiJoin(factorToAdd), factorToAdd);
addFilters(multiJoin, currJoinTree, leftIdx, newTree, filtersToAdd, false);
// LogicalFilter placed on top off the projection created above.
if (leftIdx >= 0) {
addAdditionalFilters(relBuilder, multiJoin, currJoinTree, newTree, filtersToAdd);
}
// from the new factor as we go up in the join tree
return new LoptJoinTree(relBuilder.build(), currJoinTree.getFactorTree(), newTree.getFactorTree());
}
use of org.apache.beam.vendor.calcite.v1_28_0.org.apache.calcite.util.Pair 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());
}
use of org.apache.beam.vendor.calcite.v1_28_0.org.apache.calcite.util.Pair in project calcite by apache.
the class SqlValidatorImpl method findTableColumnPair.
private Pair<String, String> findTableColumnPair(SqlIdentifier identifier, SqlValidatorScope scope) {
SqlCall call = SqlUtil.makeCall(getOperatorTable(), identifier);
if (call != null) {
return null;
}
SqlQualified qualified = scope.fullyQualify(identifier);
List<String> names = qualified.identifier.names;
if (names.size() < 2) {
return null;
}
return new Pair<>(names.get(names.size() - 2), Util.last(names));
}
use of org.apache.beam.vendor.calcite.v1_28_0.org.apache.calcite.util.Pair in project calcite by apache.
the class SqlToRelConverter method distinctify.
/**
* Having translated 'SELECT ... FROM ... [GROUP BY ...] [HAVING ...]', adds
* a relational expression to make the results unique.
*
* <p>If the SELECT clause contains duplicate expressions, adds
* {@link org.apache.calcite.rel.logical.LogicalProject}s so that we are
* grouping on the minimal set of keys. The performance gain isn't huge, but
* it is difficult to detect these duplicate expressions later.
*
* @param bb Blackboard
* @param checkForDupExprs Check for duplicate expressions
*/
private void distinctify(Blackboard bb, boolean checkForDupExprs) {
// Look for duplicate expressions in the project.
// Say we have 'select x, y, x, z'.
// Then dups will be {[2, 0]}
// and oldToNew will be {[0, 0], [1, 1], [2, 0], [3, 2]}
RelNode rel = bb.root;
if (checkForDupExprs && (rel instanceof LogicalProject)) {
LogicalProject project = (LogicalProject) rel;
final List<RexNode> projectExprs = project.getProjects();
final List<Integer> origins = new ArrayList<>();
int dupCount = 0;
for (int i = 0; i < projectExprs.size(); i++) {
int x = findExpr(projectExprs.get(i), projectExprs, i);
if (x >= 0) {
origins.add(x);
++dupCount;
} else {
origins.add(i);
}
}
if (dupCount == 0) {
distinctify(bb, false);
return;
}
final Map<Integer, Integer> squished = Maps.newHashMap();
final List<RelDataTypeField> fields = rel.getRowType().getFieldList();
final List<Pair<RexNode, String>> newProjects = Lists.newArrayList();
for (int i = 0; i < fields.size(); i++) {
if (origins.get(i) == i) {
squished.put(i, newProjects.size());
newProjects.add(RexInputRef.of2(i, fields));
}
}
rel = LogicalProject.create(rel, Pair.left(newProjects), Pair.right(newProjects));
bb.root = rel;
distinctify(bb, false);
rel = bb.root;
// Create the expressions to reverse the mapping.
// Project($0, $1, $0, $2).
final List<Pair<RexNode, String>> undoProjects = Lists.newArrayList();
for (int i = 0; i < fields.size(); i++) {
final int origin = origins.get(i);
RelDataTypeField field = fields.get(i);
undoProjects.add(Pair.of((RexNode) new RexInputRef(squished.get(origin), field.getType()), field.getName()));
}
rel = LogicalProject.create(rel, Pair.left(undoProjects), Pair.right(undoProjects));
bb.setRoot(rel, false);
return;
}
// Usual case: all of the expressions in the SELECT clause are
// different.
final ImmutableBitSet groupSet = ImmutableBitSet.range(rel.getRowType().getFieldCount());
rel = createAggregate(bb, groupSet, ImmutableList.of(groupSet), ImmutableList.<AggregateCall>of());
bb.setRoot(rel, false);
}
Aggregations