Java Code Examples for org.apache.calcite.util.ImmutableBitSet#cardinality()
The following examples show how to use
org.apache.calcite.util.ImmutableBitSet#cardinality() .
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example 1
Source File: PrelUtil.java From dremio-oss with Apache License 2.0 | 6 votes |
public static RelNode addPartialProjectOnJoin(JoinPrel join, ImmutableBitSet projected) { if ((projected != null) && ((projected.cardinality() != 0) || (projected.cardinality() != join.getRowType().getFieldCount()))) { List<RelDataTypeField> fields = join.getRowType().getFieldList(); List<RelDataType> dataTypes = new ArrayList<>(); List<String> fieldNames = new ArrayList<>(); List<RexNode> exprs = new ArrayList<>(); for (int i = 0; i < fields.size(); i++) { if (projected.get(i)) { RelDataTypeField field = fields.get(i); dataTypes.add(field.getType()); fieldNames.add(field.getName()); exprs.add(join.getCluster().getRexBuilder().makeInputRef(field.getType(), i)); } } RelDataType rowType = join.getCluster().getTypeFactory().createStructType(dataTypes, fieldNames); return ProjectPrel.create(join.getCluster(), join.getTraitSet(), join, exprs, rowType); } return join; }
Example 2
Source File: RelMdPredicates.java From Bats with Apache License 2.0 | 5 votes |
Iterable<Mapping> mappings(final RexNode predicate) { final ImmutableBitSet fields = exprFields.get(predicate); if (fields.cardinality() == 0) { return Collections.emptyList(); } return () -> new ExprsItr(fields); }
Example 3
Source File: ProjectWindowTransposeRule.java From calcite with Apache License 2.0 | 5 votes |
private int getAdjustedIndex(final int initIndex, final ImmutableBitSet beReferred, final int windowInputColumn) { if (initIndex >= windowInputColumn) { return beReferred.cardinality() + (initIndex - windowInputColumn); } else { return beReferred.get(0, initIndex).cardinality(); } }
Example 4
Source File: RelMdPredicates.java From calcite with Apache License 2.0 | 5 votes |
ExprsItr(ImmutableBitSet fields) { nextMapping = null; columns = new int[fields.cardinality()]; columnSets = new BitSet[fields.cardinality()]; iterationIdx = new int[fields.cardinality()]; for (int j = 0, i = fields.nextSetBit(0); i >= 0; i = fields .nextSetBit(i + 1), j++) { columns[j] = i; columnSets[j] = equivalence.get(i); iterationIdx[j] = 0; } firstCall = true; }
Example 5
Source File: RelMdPredicates.java From calcite with Apache License 2.0 | 5 votes |
Iterable<Mapping> mappings(final RexNode predicate) { final ImmutableBitSet fields = exprFields.get(predicate); if (fields.cardinality() == 0) { return Collections.emptyList(); } return () -> new ExprsItr(fields); }
Example 6
Source File: DremioFieldTrimmer.java From dremio-oss with Apache License 2.0 | 5 votes |
/** * Variant of {@link #trimFields(RelNode, ImmutableBitSet, Set)} for {@link ScanCrel}. */ @SuppressWarnings("unused") public TrimResult trimFields( ScanCrel crel, ImmutableBitSet fieldsUsed, Set<RelDataTypeField> extraFields) { if(fieldsUsed.cardinality() == crel.getRowType().getFieldCount()) { return result(crel, Mappings.createIdentity(crel.getRowType().getFieldCount())); } if(fieldsUsed.cardinality() == 0) { // do something similar to dummy project but avoid using a scan field. This ensures the scan // does a skipAll operation rather than projectin a useless column. final RelOptCluster cluster = crel.getCluster(); final Mapping mapping = Mappings.create(MappingType.INVERSE_SURJECTION, crel.getRowType().getFieldCount(), 1); final RexLiteral expr = cluster.getRexBuilder().makeExactLiteral(BigDecimal.ZERO); builder.push(crel); builder.project(ImmutableList.<RexNode>of(expr), ImmutableList.of("DUMMY")); return result(builder.build(), mapping); } final List<SchemaPath> paths = new ArrayList<>(); final Mapping m = Mappings.create(MappingType.PARTIAL_FUNCTION, crel.getRowType().getFieldCount(), fieldsUsed.cardinality()); int index = 0; for(int i : fieldsUsed) { paths.add(SchemaPath.getSimplePath(crel.getRowType().getFieldList().get(i).getName())); m.set(i, index); index++; } ScanCrel newCrel = crel.cloneWithProject(paths); return result(newCrel, m); }
Example 7
Source File: RexToExpr.java From dremio-oss with Apache License 2.0 | 5 votes |
public static List<NamedExpression> aggsToExpr( RelDataType rowType, RelNode input, ImmutableBitSet groupSet, List<AggregateCall> aggCalls) { final List<String> fields = rowType.getFieldNames(); final List<String> childFields = input.getRowType().getFieldNames(); final List<NamedExpression> aggExprs = Lists.newArrayList(); for (Ord<AggregateCall> aggCall : Ord.zip(aggCalls)) { int aggExprOrdinal = groupSet.cardinality() + aggCall.i; FieldReference ref = FieldReference.getWithQuotedRef(fields.get(aggExprOrdinal)); LogicalExpression expr = toExpr(aggCall.e, childFields); NamedExpression ne = new NamedExpression(expr, ref); aggExprs.add(ne); } return aggExprs; }
Example 8
Source File: RelFieldTrimmer.java From Bats with Apache License 2.0 | 5 votes |
/** * Variant of {@link #trimFields(RelNode, ImmutableBitSet, Set)} for * {@link org.apache.calcite.rel.logical.LogicalFilter}. */ public TrimResult trimFields(Filter filter, ImmutableBitSet fieldsUsed, Set<RelDataTypeField> extraFields) { final RelDataType rowType = filter.getRowType(); final int fieldCount = rowType.getFieldCount(); final RexNode conditionExpr = filter.getCondition(); final RelNode input = filter.getInput(); // We use the fields used by the consumer, plus any fields used in the // filter. final Set<RelDataTypeField> inputExtraFields = new LinkedHashSet<>(extraFields); RelOptUtil.InputFinder inputFinder = new RelOptUtil.InputFinder(inputExtraFields); inputFinder.inputBitSet.addAll(fieldsUsed); conditionExpr.accept(inputFinder); final ImmutableBitSet inputFieldsUsed = inputFinder.inputBitSet.build(); // Create input with trimmed columns. TrimResult trimResult = trimChild(filter, input, inputFieldsUsed, inputExtraFields); RelNode newInput = trimResult.left; final Mapping inputMapping = trimResult.right; // If the input is unchanged, and we need to project all columns, // there's nothing we can do. if (newInput == input && fieldsUsed.cardinality() == fieldCount) { return result(filter, Mappings.createIdentity(fieldCount)); } // Build new project expressions, and populate the mapping. final RexVisitor<RexNode> shuttle = new RexPermuteInputsShuttle(inputMapping, newInput); RexNode newConditionExpr = conditionExpr.accept(shuttle); // Use copy rather than relBuilder so that correlating variables get set. relBuilder.push(filter.copy(filter.getTraitSet(), newInput, newConditionExpr)); // The result has the same mapping as the input gave us. Sometimes we // return fields that the consumer didn't ask for, because the filter // needs them for its condition. return result(relBuilder.build(), inputMapping); }
Example 9
Source File: RelFieldTrimmer.java From calcite with Apache License 2.0 | 5 votes |
public TrimResult trimFields( Exchange exchange, ImmutableBitSet fieldsUsed, Set<RelDataTypeField> extraFields) { final RelDataType rowType = exchange.getRowType(); final int fieldCount = rowType.getFieldCount(); final RelDistribution distribution = exchange.getDistribution(); final RelNode input = exchange.getInput(); // We use the fields used by the consumer, plus any fields used as exchange // keys. final ImmutableBitSet.Builder inputFieldsUsed = fieldsUsed.rebuild(); for (int keyIndex : distribution.getKeys()) { inputFieldsUsed.set(keyIndex); } // Create input with trimmed columns. final Set<RelDataTypeField> inputExtraFields = Collections.emptySet(); final TrimResult trimResult = trimChild(exchange, input, inputFieldsUsed.build(), inputExtraFields); final RelNode newInput = trimResult.left; final Mapping inputMapping = trimResult.right; // If the input is unchanged, and we need to project all columns, // there's nothing we can do. if (newInput == input && inputMapping.isIdentity() && fieldsUsed.cardinality() == fieldCount) { return result(exchange, Mappings.createIdentity(fieldCount)); } relBuilder.push(newInput); final RelDistribution newDistribution = distribution.apply(inputMapping); relBuilder.exchange(newDistribution); return result(relBuilder.build(), inputMapping); }
Example 10
Source File: ProjectWindowTransposeRule.java From Bats with Apache License 2.0 | 5 votes |
private int getAdjustedIndex(final int initIndex, final ImmutableBitSet beReferred, final int windowInputColumn) { if (initIndex >= windowInputColumn) { return beReferred.cardinality() + (initIndex - windowInputColumn); } else { return beReferred.get(0, initIndex).cardinality(); } }
Example 11
Source File: RelMdPredicates.java From Bats with Apache License 2.0 | 5 votes |
ExprsItr(ImmutableBitSet fields) { nextMapping = null; columns = new int[fields.cardinality()]; columnSets = new BitSet[fields.cardinality()]; iterationIdx = new int[fields.cardinality()]; for (int j = 0, i = fields.nextSetBit(0); i >= 0; i = fields .nextSetBit(i + 1), j++) { columns[j] = i; columnSets[j] = equivalence.get(i); iterationIdx[j] = 0; } firstCall = true; }
Example 12
Source File: LoptMultiJoin.java From calcite with Apache License 2.0 | 4 votes |
/** * Sets weighting for each combination of factors, depending on which join * filters reference which factors. Greater weight is given to equality * conditions. Also, sets bitmaps indicating which factors are referenced by * each factor within join filters that are comparisons. */ public void setFactorWeights() { factorWeights = new int[nJoinFactors][nJoinFactors]; factorsRefByFactor = new ImmutableBitSet[nJoinFactors]; for (int i = 0; i < nJoinFactors; i++) { factorsRefByFactor[i] = ImmutableBitSet.of(); } for (RexNode joinFilter : allJoinFilters) { ImmutableBitSet factorRefs = factorsRefByJoinFilter.get(joinFilter); // don't give weights to non-comparison expressions if (!(joinFilter instanceof RexCall)) { continue; } if (!joinFilter.isA(SqlKind.COMPARISON)) { continue; } // OR the factors referenced in this join filter into the // bitmaps corresponding to each of the factors; however, // exclude the bit corresponding to the factor itself for (int factor : factorRefs) { factorsRefByFactor[factor] = factorsRefByFactor[factor] .rebuild() .addAll(factorRefs) .clear(factor) .build(); } if (factorRefs.cardinality() == 2) { int leftFactor = factorRefs.nextSetBit(0); int rightFactor = factorRefs.nextSetBit(leftFactor + 1); final RexCall call = (RexCall) joinFilter; ImmutableBitSet leftFields = fieldBitmap(call.getOperands().get(0)); ImmutableBitSet leftBitmap = factorBitmap(leftFields); // filter contains only two factor references, one on each // side of the operator int weight; if (leftBitmap.cardinality() == 1) { // give higher weight to equi-joins switch (joinFilter.getKind()) { case EQUALS: weight = 3; break; default: weight = 2; } } else { // cross product of two tables weight = 1; } setFactorWeight(weight, leftFactor, rightFactor); } else { // multiple factor references -- set a weight for each // combination of factors referenced within the filter final List<Integer> list = ImmutableIntList.copyOf(factorRefs); for (int outer : list) { for (int inner : list) { if (outer != inner) { setFactorWeight(1, outer, inner); } } } } } }
Example 13
Source File: RelMdDistinctRowCount.java From dremio-oss with Apache License 2.0 | 4 votes |
private Double getDistinctRowCountFromEstimateRowCount(RelNode rel, RelMetadataQuery mq, ImmutableBitSet groupKey, RexNode predicate) { final int groupKeySize = groupKey.cardinality(); return rel.estimateRowCount(mq) * (1.0 - Math.pow(0.9, groupKeySize)) * RelMdUtil.guessSelectivity(predicate); }
Example 14
Source File: LoptMultiJoin.java From Bats with Apache License 2.0 | 4 votes |
/** * Sets weighting for each combination of factors, depending on which join * filters reference which factors. Greater weight is given to equality * conditions. Also, sets bitmaps indicating which factors are referenced by * each factor within join filters that are comparisons. */ public void setFactorWeights() { factorWeights = new int[nJoinFactors][nJoinFactors]; factorsRefByFactor = new ImmutableBitSet[nJoinFactors]; for (int i = 0; i < nJoinFactors; i++) { factorsRefByFactor[i] = ImmutableBitSet.of(); } for (RexNode joinFilter : allJoinFilters) { ImmutableBitSet factorRefs = factorsRefByJoinFilter.get(joinFilter); // don't give weights to non-comparison expressions if (!(joinFilter instanceof RexCall)) { continue; } if (!joinFilter.isA(SqlKind.COMPARISON)) { continue; } // OR the factors referenced in this join filter into the // bitmaps corresponding to each of the factors; however, // exclude the bit corresponding to the factor itself for (int factor : factorRefs) { factorsRefByFactor[factor] = factorsRefByFactor[factor] .rebuild() .addAll(factorRefs) .clear(factor) .build(); } if (factorRefs.cardinality() == 2) { int leftFactor = factorRefs.nextSetBit(0); int rightFactor = factorRefs.nextSetBit(leftFactor + 1); final RexCall call = (RexCall) joinFilter; ImmutableBitSet leftFields = fieldBitmap(call.getOperands().get(0)); ImmutableBitSet leftBitmap = factorBitmap(leftFields); // filter contains only two factor references, one on each // side of the operator int weight; if (leftBitmap.cardinality() == 1) { // give higher weight to equi-joins switch (joinFilter.getKind()) { case EQUALS: weight = 3; break; default: weight = 2; } } else { // cross product of two tables weight = 1; } setFactorWeight(weight, leftFactor, rightFactor); } else { // multiple factor references -- set a weight for each // combination of factors referenced within the filter final List<Integer> list = ImmutableIntList.copyOf(factorRefs); for (int outer : list) { for (int inner : list) { if (outer != inner) { setFactorWeight(1, outer, inner); } } } } } }
Example 15
Source File: ProfilerImpl.java From calcite with Apache License 2.0 | 4 votes |
/** Populates {@code spaces} with the next batch. * Returns an empty list if done. */ List<Space> nextBatch(int pass) { final List<Space> spaces = new ArrayList<>(); loop: for (;;) { if (spaces.size() >= combinationsPerPass) { // We have enough for the next pass. return spaces; } // First, see if there is a space we did have room for last pass. final ImmutableBitSet ordinals = spaceQueue.poll(); if (ordinals != null) { final Space space = new Space(this, ordinals, toColumns(ordinals)); spaces.add(space); if (ordinals.cardinality() == 1) { singletonSpaces.set(ordinals.nth(0), space); } } else { // Next, take a space that was done last time, generate its // successors, and add the interesting ones to the space queue. for (;;) { final Space doneSpace = doneQueue.poll(); if (doneSpace == null) { // There are no more done spaces. We're done. return spaces; } if (doneSpace.columnOrdinals.cardinality() > 4) { // Do not generate successors for groups with lots of columns, // probably initial groups continue; } for (Column column : columns) { if (!doneSpace.columnOrdinals.get(column.ordinal)) { if (pass == 0 || doneSpace.columnOrdinals.cardinality() == 0 || !containsKey( doneSpace.columnOrdinals.set(column.ordinal)) && predicate.test(Pair.of(doneSpace, column))) { final ImmutableBitSet nextOrdinals = doneSpace.columnOrdinals.set(column.ordinal); if (resultSet.add(nextOrdinals)) { spaceQueue.add(nextOrdinals); } } } } // We've converted at a space into at least one interesting // successor. if (!spaceQueue.isEmpty()) { continue loop; } } } } }
Example 16
Source File: AggregateMergeRule.java From calcite with Apache License 2.0 | 4 votes |
public void onMatch(RelOptRuleCall call) { final Aggregate topAgg = call.rel(0); final Aggregate bottomAgg = call.rel(1); if (topAgg.getGroupCount() > bottomAgg.getGroupCount()) { return; } final ImmutableBitSet bottomGroupSet = bottomAgg.getGroupSet(); final Map<Integer, Integer> map = new HashMap<>(); bottomGroupSet.forEach(v -> map.put(map.size(), v)); for (int k : topAgg.getGroupSet()) { if (!map.containsKey(k)) { return; } } // top aggregate keys must be subset of lower aggregate keys final ImmutableBitSet topGroupSet = topAgg.getGroupSet().permute(map); if (!bottomGroupSet.contains(topGroupSet)) { return; } boolean hasEmptyGroup = topAgg.getGroupSets() .stream().anyMatch(n -> n.isEmpty()); final List<AggregateCall> finalCalls = new ArrayList<>(); for (AggregateCall topCall : topAgg.getAggCallList()) { if (!isAggregateSupported(topCall) || topCall.getArgList().size() == 0) { return; } // Make sure top aggregate argument refers to one of the aggregate int bottomIndex = topCall.getArgList().get(0) - bottomGroupSet.cardinality(); if (bottomIndex >= bottomAgg.getAggCallList().size() || bottomIndex < 0) { return; } AggregateCall bottomCall = bottomAgg.getAggCallList().get(bottomIndex); // Should not merge if top agg with empty group keys and the lower agg // function is COUNT, because in case of empty input for lower agg, // the result is empty, if we merge them, we end up with 1 result with // 0, which is wrong. if (!isAggregateSupported(bottomCall) || (bottomCall.getAggregation() == SqlStdOperatorTable.COUNT && hasEmptyGroup)) { return; } SqlSplittableAggFunction splitter = Objects.requireNonNull( bottomCall.getAggregation().unwrap(SqlSplittableAggFunction.class)); AggregateCall finalCall = splitter.merge(topCall, bottomCall); // fail to merge the aggregate call, bail out if (finalCall == null) { return; } finalCalls.add(finalCall); } // re-map grouping sets ImmutableList<ImmutableBitSet> newGroupingSets = null; if (topAgg.getGroupType() != Group.SIMPLE) { newGroupingSets = ImmutableBitSet.ORDERING.immutableSortedCopy( ImmutableBitSet.permute(topAgg.getGroupSets(), map)); } final Aggregate finalAgg = topAgg.copy(topAgg.getTraitSet(), bottomAgg.getInput(), topGroupSet, newGroupingSets, finalCalls); call.transformTo(finalAgg); }
Example 17
Source File: RelMdColumnUniqueness.java From calcite with Apache License 2.0 | 4 votes |
public Boolean areColumnsUnique(Join rel, RelMetadataQuery mq, ImmutableBitSet columns, boolean ignoreNulls) { columns = decorateWithConstantColumnsFromPredicates(columns, rel, mq); if (columns.cardinality() == 0) { return false; } final RelNode left = rel.getLeft(); final RelNode right = rel.getRight(); // Semi or anti join should ignore uniqueness of the right input. if (!rel.getJoinType().projectsRight()) { return mq.areColumnsUnique(left, columns, ignoreNulls); } // Divide up the input column mask into column masks for the left and // right sides of the join final Pair<ImmutableBitSet, ImmutableBitSet> leftAndRightColumns = splitLeftAndRightColumns(rel.getLeft().getRowType().getFieldCount(), columns); final ImmutableBitSet leftColumns = leftAndRightColumns.left; final ImmutableBitSet rightColumns = leftAndRightColumns.right; // for FULL OUTER JOIN if columns contain column from both inputs it is not // guaranteed that the result will be unique if (!ignoreNulls && rel.getJoinType() == JoinRelType.FULL && leftColumns.cardinality() > 0 && rightColumns.cardinality() > 0) { return false; } // If the original column mask contains columns from both the left and // right hand side, then the columns are unique if and only if they're // unique for their respective join inputs Boolean leftUnique = mq.areColumnsUnique(left, leftColumns, ignoreNulls); Boolean rightUnique = mq.areColumnsUnique(right, rightColumns, ignoreNulls); if ((leftColumns.cardinality() > 0) && (rightColumns.cardinality() > 0)) { if ((leftUnique == null) || (rightUnique == null)) { return null; } else { return leftUnique && rightUnique; } } // If we're only trying to determine uniqueness for columns that // originate from one join input, then determine if the equijoin // columns from the other join input are unique. If they are, then // the columns are unique for the entire join if they're unique for // the corresponding join input, provided that input is not null // generating. final JoinInfo joinInfo = rel.analyzeCondition(); if (leftColumns.cardinality() > 0) { if (rel.getJoinType().generatesNullsOnLeft()) { return false; } Boolean rightJoinColsUnique = mq.areColumnsUnique(right, joinInfo.rightSet(), ignoreNulls); if ((rightJoinColsUnique == null) || (leftUnique == null)) { return null; } return rightJoinColsUnique && leftUnique; } else if (rightColumns.cardinality() > 0) { if (rel.getJoinType().generatesNullsOnRight()) { return false; } Boolean leftJoinColsUnique = mq.areColumnsUnique(left, joinInfo.leftSet(), ignoreNulls); if ((leftJoinColsUnique == null) || (rightUnique == null)) { return null; } return leftJoinColsUnique && rightUnique; } throw new AssertionError(); }
Example 18
Source File: MaterializedViewAggregateRule.java From calcite with Apache License 2.0 | 4 votes |
@Override protected RelNode createUnion(RelBuilder relBuilder, RexBuilder rexBuilder, RelNode topProject, RelNode unionInputQuery, RelNode unionInputView) { // Union relBuilder.push(unionInputQuery); relBuilder.push(unionInputView); relBuilder.union(true); List<RexNode> exprList = new ArrayList<>(relBuilder.peek().getRowType().getFieldCount()); List<String> nameList = new ArrayList<>(relBuilder.peek().getRowType().getFieldCount()); for (int i = 0; i < relBuilder.peek().getRowType().getFieldCount(); i++) { // We can take unionInputQuery as it is query based. RelDataTypeField field = unionInputQuery.getRowType().getFieldList().get(i); exprList.add( rexBuilder.ensureType( field.getType(), rexBuilder.makeInputRef(relBuilder.peek(), i), true)); nameList.add(field.getName()); } relBuilder.project(exprList, nameList); // Rollup aggregate Aggregate aggregate = (Aggregate) unionInputQuery; final ImmutableBitSet groupSet = ImmutableBitSet.range(aggregate.getGroupCount()); final List<AggCall> aggregateCalls = new ArrayList<>(); for (int i = 0; i < aggregate.getAggCallList().size(); i++) { AggregateCall aggCall = aggregate.getAggCallList().get(i); if (aggCall.isDistinct()) { // Cannot ROLLUP distinct return null; } SqlAggFunction rollupAgg = getRollup(aggCall.getAggregation()); if (rollupAgg == null) { // Cannot rollup this aggregate, bail out return null; } final RexInputRef operand = rexBuilder.makeInputRef(relBuilder.peek(), aggregate.getGroupCount() + i); aggregateCalls.add( relBuilder.aggregateCall(rollupAgg, operand) .distinct(aggCall.isDistinct()) .approximate(aggCall.isApproximate()) .as(aggCall.name)); } RelNode prevNode = relBuilder.peek(); RelNode result = relBuilder .aggregate(relBuilder.groupKey(groupSet), aggregateCalls) .build(); if (prevNode == result && groupSet.cardinality() != result.getRowType().getFieldCount()) { // Aggregate was not inserted but we need to prune columns result = relBuilder .push(result) .project(relBuilder.fields(groupSet)) .build(); } if (topProject != null) { // Top project return topProject.copy(topProject.getTraitSet(), ImmutableList.of(result)); } // Result return result; }
Example 19
Source File: RelMdColumnUniqueness.java From Bats with Apache License 2.0 | 4 votes |
public Boolean areColumnsUnique(Join rel, RelMetadataQuery mq, ImmutableBitSet columns, boolean ignoreNulls) { if (columns.cardinality() == 0) { return false; } final RelNode left = rel.getLeft(); final RelNode right = rel.getRight(); // Divide up the input column mask into column masks for the left and // right sides of the join final Pair<ImmutableBitSet, ImmutableBitSet> leftAndRightColumns = splitLeftAndRightColumns(rel.getLeft().getRowType().getFieldCount(), columns); final ImmutableBitSet leftColumns = leftAndRightColumns.left; final ImmutableBitSet rightColumns = leftAndRightColumns.right; // If the original column mask contains columns from both the left and // right hand side, then the columns are unique if and only if they're // unique for their respective join inputs Boolean leftUnique = mq.areColumnsUnique(left, leftColumns, ignoreNulls); Boolean rightUnique = mq.areColumnsUnique(right, rightColumns, ignoreNulls); if ((leftColumns.cardinality() > 0) && (rightColumns.cardinality() > 0)) { if ((leftUnique == null) || (rightUnique == null)) { return null; } else { return leftUnique && rightUnique; } } // If we're only trying to determine uniqueness for columns that // originate from one join input, then determine if the equijoin // columns from the other join input are unique. If they are, then // the columns are unique for the entire join if they're unique for // the corresponding join input, provided that input is not null // generating. final JoinInfo joinInfo = rel.analyzeCondition(); if (leftColumns.cardinality() > 0) { if (rel.getJoinType().generatesNullsOnLeft()) { return false; } Boolean rightJoinColsUnique = mq.areColumnsUnique(right, joinInfo.rightSet(), ignoreNulls); if ((rightJoinColsUnique == null) || (leftUnique == null)) { return null; } return rightJoinColsUnique && leftUnique; } else if (rightColumns.cardinality() > 0) { if (rel.getJoinType().generatesNullsOnRight()) { return false; } Boolean leftJoinColsUnique = mq.areColumnsUnique(left, joinInfo.leftSet(), ignoreNulls); if ((leftJoinColsUnique == null) || (rightUnique == null)) { return null; } return leftJoinColsUnique && rightUnique; } throw new AssertionError(); }
Example 20
Source File: LoptOptimizeJoinRule.java From calcite with Apache License 2.0 | 4 votes |
/** * Locates pairs of joins that are self-joins where the join can be removed * because the join condition between the two factors is an equality join on * unique keys. * * @param multiJoin join factors being optimized */ private void findRemovableSelfJoins(RelMetadataQuery mq, LoptMultiJoin multiJoin) { // Candidates for self-joins must be simple factors Map<Integer, RelOptTable> simpleFactors = getSimpleFactors(mq, multiJoin); // See if a simple factor is repeated and therefore potentially is // part of a self-join. Restrict each factor to at most one // self-join. final List<RelOptTable> repeatedTables = new ArrayList<>(); final TreeSet<Integer> sortedFactors = new TreeSet<>(); sortedFactors.addAll(simpleFactors.keySet()); final Map<Integer, Integer> selfJoinPairs = new HashMap<>(); Integer [] factors = sortedFactors.toArray(new Integer[0]); for (int i = 0; i < factors.length; i++) { if (repeatedTables.contains(simpleFactors.get(factors[i]))) { continue; } for (int j = i + 1; j < factors.length; j++) { int leftFactor = factors[i]; int rightFactor = factors[j]; if (simpleFactors.get(leftFactor).getQualifiedName().equals( simpleFactors.get(rightFactor).getQualifiedName())) { selfJoinPairs.put(leftFactor, rightFactor); repeatedTables.add(simpleFactors.get(leftFactor)); break; } } } // From the candidate self-join pairs, determine if there is // the appropriate join condition between the two factors that will // allow the join to be removed. for (Integer factor1 : selfJoinPairs.keySet()) { final int factor2 = selfJoinPairs.get(factor1); final List<RexNode> selfJoinFilters = new ArrayList<>(); for (RexNode filter : multiJoin.getJoinFilters()) { ImmutableBitSet joinFactors = multiJoin.getFactorsRefByJoinFilter(filter); if ((joinFactors.cardinality() == 2) && joinFactors.get(factor1) && joinFactors.get(factor2)) { selfJoinFilters.add(filter); } } if ((selfJoinFilters.size() > 0) && isSelfJoinFilterUnique( mq, multiJoin, factor1, factor2, selfJoinFilters)) { multiJoin.addRemovableSelfJoinPair(factor1, factor2); } } }