use of org.apache.beam.vendor.calcite.v1_28_0.org.apache.calcite.rel.core.Union in project calcite by apache.
the class UnionMergeRule method onMatch.
@Override
public void onMatch(RelOptRuleCall call) {
final SetOp topOp = call.rel(0);
@SuppressWarnings("unchecked") final Class<? extends SetOp> setOpClass = (Class) operands.get(0).getMatchedClass();
// For Union and Intersect, we want to combine the set-op that's in the
// second input first.
//
// For example, we reduce
// Union(Union(a, b), Union(c, d))
// to
// Union(Union(a, b), c, d)
// in preference to
// Union(a, b, Union(c, d))
//
// But for Minus, we can only reduce the left input. It is not valid to
// reduce
// Minus(a, Minus(b, c))
// to
// Minus(a, b, c)
//
// Hence, that's why the rule pattern matches on generic RelNodes rather
// than explicit sub-classes of SetOp. By doing so, and firing this rule
// in a bottom-up order, it allows us to only specify a single
// pattern for this rule.
final SetOp bottomOp;
if (setOpClass.isInstance(call.rel(2)) && !Minus.class.isAssignableFrom(setOpClass)) {
bottomOp = call.rel(2);
} else if (setOpClass.isInstance(call.rel(1))) {
bottomOp = call.rel(1);
} else {
return;
}
// In case (2), all operators become DISTINCT.
if (topOp.all && !bottomOp.all) {
return;
}
// Combine the inputs from the bottom set-op with the other inputs from
// the top set-op.
final RelBuilder relBuilder = call.builder();
if (setOpClass.isInstance(call.rel(2)) && !Minus.class.isAssignableFrom(setOpClass)) {
relBuilder.push(topOp.getInput(0));
relBuilder.pushAll(bottomOp.getInputs());
// topOp.getInputs().size() may be more than 2
for (int index = 2; index < topOp.getInputs().size(); index++) {
relBuilder.push(topOp.getInput(index));
}
} else {
relBuilder.pushAll(bottomOp.getInputs());
relBuilder.pushAll(Util.skip(topOp.getInputs()));
}
int n = bottomOp.getInputs().size() + topOp.getInputs().size() - 1;
if (topOp instanceof Union) {
relBuilder.union(topOp.all, n);
} else if (topOp instanceof Intersect) {
relBuilder.intersect(topOp.all, n);
} else if (topOp instanceof Minus) {
relBuilder.minus(topOp.all, n);
}
call.transformTo(relBuilder.build());
}
use of org.apache.beam.vendor.calcite.v1_28_0.org.apache.calcite.rel.core.Union in project calcite by apache.
the class UnionToDistinctRule method onMatch.
// ~ Methods ----------------------------------------------------------------
@Override
public void onMatch(RelOptRuleCall call) {
final Union union = call.rel(0);
final RelBuilder relBuilder = call.builder();
relBuilder.pushAll(union.getInputs());
relBuilder.union(true, union.getInputs().size());
relBuilder.distinct();
call.transformTo(relBuilder.build());
}
use of org.apache.beam.vendor.calcite.v1_28_0.org.apache.calcite.rel.core.Union in project calcite by apache.
the class RelBuilder method rewriteAggregateWithDuplicateGroupSets.
/**
* The {@code GROUP_ID()} function is used to distinguish duplicate groups.
* However, as Aggregate normalizes group sets to canonical form (i.e.,
* flatten, sorting, redundancy removal), this information is lost in RelNode.
* Therefore, it is impossible to implement the function in runtime.
*
* <p>To fill this gap, an aggregation query that contains duplicate group
* sets is rewritten into a Union of Aggregate operators whose group sets are
* distinct. The number of inputs to the Union is equal to the maximum number
* of duplicates. In the {@code N}th input to the Union, calls to the
* {@code GROUP_ID} aggregate function are replaced by the integer literal
* {@code N}.
*
* <p>This method also handles the case where group sets are distinct but
* there is a call to {@code GROUP_ID}. That call is replaced by the integer
* literal {@code 0}.
*
* <p>Also see the discussion in
* <a href="https://issues.apache.org/jira/browse/CALCITE-1824">[CALCITE-1824]
* GROUP_ID returns wrong result</a> and
* <a href="https://issues.apache.org/jira/browse/CALCITE-4748">[CALCITE-4748]
* If there are duplicate GROUPING SETS, Calcite should return duplicate
* rows</a>.
*/
private RelBuilder rewriteAggregateWithDuplicateGroupSets(ImmutableBitSet groupSet, ImmutableSortedMultiset<ImmutableBitSet> groupSets, List<AggCall> aggregateCalls) {
final List<String> fieldNamesIfNoRewrite = Aggregate.deriveRowType(getTypeFactory(), peek().getRowType(), false, groupSet, groupSets.asList(), aggregateCalls.stream().map(c -> ((AggCallPlus) c).aggregateCall()).collect(Util.toImmutableList())).getFieldNames();
// If n duplicates exist for a particular grouping, the {@code GROUP_ID()}
// function produces values in the range 0 to n-1. For each value,
// we need to figure out the corresponding group sets.
//
// For example, "... GROUPING SETS (a, a, b, c, c, c, c)"
// (i) The max value of the GROUP_ID() function returns is 3
// (ii) GROUPING SETS (a, b, c) produces value 0,
// GROUPING SETS (a, c) produces value 1,
// GROUPING SETS (c) produces value 2
// GROUPING SETS (c) produces value 3
final Map<Integer, Set<ImmutableBitSet>> groupIdToGroupSets = new HashMap<>();
int maxGroupId = 0;
for (Multiset.Entry<ImmutableBitSet> entry : groupSets.entrySet()) {
int groupId = entry.getCount() - 1;
if (groupId > maxGroupId) {
maxGroupId = groupId;
}
for (int i = 0; i <= groupId; i++) {
groupIdToGroupSets.computeIfAbsent(i, k -> Sets.newTreeSet(ImmutableBitSet.COMPARATOR)).add(entry.getElement());
}
}
// AggregateCall list without GROUP_ID function
final List<AggCall> aggregateCallsWithoutGroupId = new ArrayList<>(aggregateCalls);
aggregateCallsWithoutGroupId.removeIf(RelBuilder::isGroupId);
// For each group id value, we first construct an Aggregate without
// GROUP_ID() function call, and then create a Project node on top of it.
// The Project adds literal value for group id in right position.
final Frame frame = stack.pop();
for (int groupId = 0; groupId <= maxGroupId; groupId++) {
// Create the Aggregate node without GROUP_ID() call
stack.push(frame);
aggregate(groupKey(groupSet, castNonNull(groupIdToGroupSets.get(groupId))), aggregateCallsWithoutGroupId);
final List<RexNode> selectList = new ArrayList<>();
final int groupExprLength = groupSet.cardinality();
// Project fields in group by expressions
for (int i = 0; i < groupExprLength; i++) {
selectList.add(field(i));
}
// Project fields in aggregate calls
int groupIdCount = 0;
for (int i = 0; i < aggregateCalls.size(); i++) {
if (isGroupId(aggregateCalls.get(i))) {
selectList.add(getRexBuilder().makeExactLiteral(BigDecimal.valueOf(groupId), getTypeFactory().createSqlType(SqlTypeName.BIGINT)));
groupIdCount++;
} else {
selectList.add(field(groupExprLength + i - groupIdCount));
}
}
project(selectList, fieldNamesIfNoRewrite);
}
return union(true, maxGroupId + 1);
}
use of org.apache.beam.vendor.calcite.v1_28_0.org.apache.calcite.rel.core.Union in project Mycat2 by MyCATApache.
the class MycatAggregateUnionTransposeRule method onMatch.
@Override
public void onMatch(RelOptRuleCall call) {
Aggregate aggRel = call.rel(0);
Union union = call.rel(1);
if (!union.all) {
// which yields 25 (incorrect).
return;
}
int groupCount = aggRel.getGroupSet().cardinality();
List<AggregateCall> transformedAggCalls = transformAggCalls(aggRel.copy(aggRel.getTraitSet(), aggRel.getInput(), aggRel.getGroupSet(), null, aggRel.getAggCallList()), groupCount, aggRel.getAggCallList());
if (transformedAggCalls == null) {
// which we can't handle
return;
}
// create corresponding aggregates on top of each union child
final RelBuilder relBuilder = call.builder();
int transformCount = 0;
final RelMetadataQuery mq = call.getMetadataQuery();
for (RelNode input : union.getInputs()) {
boolean alreadyUnique = RelMdUtil.areColumnsDefinitelyUnique(mq, input, aggRel.getGroupSet());
relBuilder.push(input);
if (!alreadyUnique) {
++transformCount;
relBuilder.aggregate(relBuilder.groupKey(aggRel.getGroupSet()), aggRel.getAggCallList());
}
}
if (transformCount == 0) {
// planners would succumb)
return;
}
// create a new union whose children are the aggregates created above
relBuilder.union(true, union.getInputs().size());
relBuilder.aggregate(relBuilder.groupKey(aggRel.getGroupSet(), (Iterable<ImmutableBitSet>) aggRel.getGroupSets()), transformedAggCalls);
call.transformTo(relBuilder.build());
}
use of org.apache.beam.vendor.calcite.v1_28_0.org.apache.calcite.rel.core.Union in project Mycat2 by MyCATApache.
the class ToLogicalConverter method visit.
@Override
public RelNode visit(RelNode relNode) {
if (relNode instanceof Aggregate) {
final Aggregate agg = (Aggregate) relNode;
return relBuilder.push(visit(agg.getInput())).aggregate(relBuilder.groupKey(agg.getGroupSet(), (Iterable<ImmutableBitSet>) agg.groupSets), agg.getAggCallList()).build();
}
if (relNode instanceof TableScan) {
return visit((TableScan) relNode);
}
if (relNode instanceof Filter) {
final Filter filter = (Filter) relNode;
return relBuilder.push(visit(filter.getInput())).filter(filter.getCondition()).build();
}
if (relNode instanceof Project) {
final Project project = (Project) relNode;
return relBuilder.push(visit(project.getInput())).project(project.getProjects(), project.getRowType().getFieldNames()).build();
}
if (relNode instanceof Union) {
final Union union = (Union) relNode;
for (RelNode rel : union.getInputs()) {
relBuilder.push(visit(rel));
}
return relBuilder.union(union.all, union.getInputs().size()).build();
}
if (relNode instanceof Intersect) {
final Intersect intersect = (Intersect) relNode;
for (RelNode rel : intersect.getInputs()) {
relBuilder.push(visit(rel));
}
return relBuilder.intersect(intersect.all, intersect.getInputs().size()).build();
}
if (relNode instanceof Minus) {
final Minus minus = (Minus) relNode;
for (RelNode rel : minus.getInputs()) {
relBuilder.push(visit(rel));
}
return relBuilder.minus(minus.all, minus.getInputs().size()).build();
}
if (relNode instanceof Join) {
final Join join = (Join) relNode;
return relBuilder.push(visit(join.getLeft())).push(visit(join.getRight())).join(join.getJoinType(), join.getCondition()).build();
}
if (relNode instanceof Correlate) {
final Correlate corr = (Correlate) relNode;
return relBuilder.push(visit(corr.getLeft())).push(visit(corr.getRight())).join(corr.getJoinType(), relBuilder.literal(true), corr.getVariablesSet()).build();
}
if (relNode instanceof Values) {
final Values values = (Values) relNode;
return relBuilder.values(values.tuples, values.getRowType()).build();
}
if (relNode instanceof Sort) {
final Sort sort = (Sort) relNode;
return LogicalSort.create(visit(sort.getInput()), sort.getCollation(), sort.offset, sort.fetch);
}
if (relNode instanceof Window) {
final Window window = (Window) relNode;
final RelNode input = visit(window.getInput());
return LogicalWindow.create(input.getTraitSet(), input, window.constants, window.getRowType(), window.groups);
}
if (relNode instanceof Calc) {
final Calc calc = (Calc) relNode;
return LogicalCalc.create(visit(calc.getInput()), calc.getProgram());
}
if (relNode instanceof TableModify) {
final TableModify tableModify = (TableModify) relNode;
final RelNode input = visit(tableModify.getInput());
return LogicalTableModify.create(tableModify.getTable(), tableModify.getCatalogReader(), input, tableModify.getOperation(), tableModify.getUpdateColumnList(), tableModify.getSourceExpressionList(), tableModify.isFlattened());
}
// }
if (relNode instanceof EnumerableInterpreter) {
return visit(((SingleRel) relNode).getInput());
}
if (relNode instanceof EnumerableLimit) {
final EnumerableLimit limit = (EnumerableLimit) relNode;
RelNode logicalInput = visit(limit.getInput());
RelCollation collation = RelCollations.of();
if (logicalInput instanceof Sort) {
collation = ((Sort) logicalInput).collation;
logicalInput = ((Sort) logicalInput).getInput();
}
return LogicalSort.create(logicalInput, collation, limit.offset, limit.fetch);
}
if (relNode instanceof Uncollect) {
final Uncollect uncollect = (Uncollect) relNode;
final RelNode input = visit(uncollect.getInput());
return Uncollect.create(input.getTraitSet(), input, uncollect.withOrdinality, Collections.emptyList());
}
throw new AssertionError("Need to implement logical converter for " + relNode.getClass().getName());
}
Aggregations