use of org.apache.beam.vendor.calcite.v1_28_0.org.apache.calcite.rel.core.AggregateCall 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);
}
use of org.apache.beam.vendor.calcite.v1_28_0.org.apache.calcite.rel.core.AggregateCall in project calcite by apache.
the class RelDecorrelator method decorrelateRel.
/**
* Rewrites a {@link LogicalAggregate}.
*
* @param rel Aggregate to rewrite
*/
public Frame decorrelateRel(LogicalAggregate rel) {
if (rel.getGroupType() != Aggregate.Group.SIMPLE) {
throw new AssertionError(Bug.CALCITE_461_FIXED);
}
// Aggregate itself should not reference corVars.
assert !cm.mapRefRelToCorRef.containsKey(rel);
final RelNode oldInput = rel.getInput();
final Frame frame = getInvoke(oldInput, rel);
if (frame == null) {
// If input has not been rewritten, do not rewrite this rel.
return null;
}
final RelNode newInput = frame.r;
// map from newInput
Map<Integer, Integer> mapNewInputToProjOutputs = new HashMap<>();
final int oldGroupKeyCount = rel.getGroupSet().cardinality();
// Project projects the original expressions,
// plus any correlated variables the input wants to pass along.
final List<Pair<RexNode, String>> projects = Lists.newArrayList();
List<RelDataTypeField> newInputOutput = newInput.getRowType().getFieldList();
int newPos = 0;
// oldInput has the original group by keys in the front.
final NavigableMap<Integer, RexLiteral> omittedConstants = new TreeMap<>();
for (int i = 0; i < oldGroupKeyCount; i++) {
final RexLiteral constant = projectedLiteral(newInput, i);
if (constant != null) {
// Exclude constants. Aggregate({true}) occurs because Aggregate({})
// would generate 1 row even when applied to an empty table.
omittedConstants.put(i, constant);
continue;
}
int newInputPos = frame.oldToNewOutputs.get(i);
projects.add(RexInputRef.of2(newInputPos, newInputOutput));
mapNewInputToProjOutputs.put(newInputPos, newPos);
newPos++;
}
final SortedMap<CorDef, Integer> corDefOutputs = new TreeMap<>();
if (!frame.corDefOutputs.isEmpty()) {
// position oldGroupKeyCount.
for (Map.Entry<CorDef, Integer> entry : frame.corDefOutputs.entrySet()) {
projects.add(RexInputRef.of2(entry.getValue(), newInputOutput));
corDefOutputs.put(entry.getKey(), newPos);
mapNewInputToProjOutputs.put(entry.getValue(), newPos);
newPos++;
}
}
// add the remaining fields
final int newGroupKeyCount = newPos;
for (int i = 0; i < newInputOutput.size(); i++) {
if (!mapNewInputToProjOutputs.containsKey(i)) {
projects.add(RexInputRef.of2(i, newInputOutput));
mapNewInputToProjOutputs.put(i, newPos);
newPos++;
}
}
assert newPos == newInputOutput.size();
// This Project will be what the old input maps to,
// replacing any previous mapping from old input).
RelNode newProject = relBuilder.push(newInput).projectNamed(Pair.left(projects), Pair.right(projects), true).build();
// update mappings:
// oldInput ----> newInput
//
// newProject
// |
// oldInput ----> newInput
//
// is transformed to
//
// oldInput ----> newProject
// |
// newInput
Map<Integer, Integer> combinedMap = Maps.newHashMap();
for (Integer oldInputPos : frame.oldToNewOutputs.keySet()) {
combinedMap.put(oldInputPos, mapNewInputToProjOutputs.get(frame.oldToNewOutputs.get(oldInputPos)));
}
register(oldInput, newProject, combinedMap, corDefOutputs);
// now it's time to rewrite the Aggregate
final ImmutableBitSet newGroupSet = ImmutableBitSet.range(newGroupKeyCount);
List<AggregateCall> newAggCalls = Lists.newArrayList();
List<AggregateCall> oldAggCalls = rel.getAggCallList();
int oldInputOutputFieldCount = rel.getGroupSet().cardinality();
int newInputOutputFieldCount = newGroupSet.cardinality();
int i = -1;
for (AggregateCall oldAggCall : oldAggCalls) {
++i;
List<Integer> oldAggArgs = oldAggCall.getArgList();
List<Integer> aggArgs = Lists.newArrayList();
// for the argument.
for (int oldPos : oldAggArgs) {
aggArgs.add(combinedMap.get(oldPos));
}
final int filterArg = oldAggCall.filterArg < 0 ? oldAggCall.filterArg : combinedMap.get(oldAggCall.filterArg);
newAggCalls.add(oldAggCall.adaptTo(newProject, aggArgs, filterArg, oldGroupKeyCount, newGroupKeyCount));
// The old to new output position mapping will be the same as that
// of newProject, plus any aggregates that the oldAgg produces.
combinedMap.put(oldInputOutputFieldCount + i, newInputOutputFieldCount + i);
}
relBuilder.push(LogicalAggregate.create(newProject, newGroupSet, null, newAggCalls));
if (!omittedConstants.isEmpty()) {
final List<RexNode> postProjects = new ArrayList<>(relBuilder.fields());
for (Map.Entry<Integer, RexLiteral> entry : omittedConstants.descendingMap().entrySet()) {
postProjects.add(entry.getKey() + frame.corDefOutputs.size(), entry.getValue());
}
relBuilder.project(postProjects);
}
// located at the same position as the input newProject.
return register(rel, relBuilder.build(), combinedMap, corDefOutputs);
}
use of org.apache.beam.vendor.calcite.v1_28_0.org.apache.calcite.rel.core.AggregateCall in project calcite by apache.
the class RelOptUtil method createExistsPlan.
/**
* Creates a plan suitable for use in <code>EXISTS</code> or <code>IN</code>
* statements.
*
* @see org.apache.calcite.sql2rel.SqlToRelConverter#convertExists
*
* @param seekRel A query rel, for example the resulting rel from 'select *
* from emp' or 'values (1,2,3)' or '('Foo', 34)'.
* @param subQueryType Sub-query type
* @param logic Whether to use 2- or 3-valued boolean logic
* @param notIn Whether the operator is NOT IN
* @param relBuilder Builder for relational expressions
*
* @return A pair of a relational expression which outer joins a boolean
* condition column, and a numeric offset. The offset is 2 if column 0 is
* the number of rows and column 1 is the number of rows with not-null keys;
* 0 otherwise.
*/
public static Exists createExistsPlan(RelNode seekRel, SubQueryType subQueryType, Logic logic, boolean notIn, RelBuilder relBuilder) {
switch(subQueryType) {
case SCALAR:
return new Exists(seekRel, false, true);
}
switch(logic) {
case TRUE_FALSE_UNKNOWN:
case UNKNOWN_AS_TRUE:
if (notIn && !containsNullableFields(seekRel)) {
logic = Logic.TRUE_FALSE;
}
}
RelNode ret = seekRel;
final RelOptCluster cluster = seekRel.getCluster();
final RexBuilder rexBuilder = cluster.getRexBuilder();
final int keyCount = ret.getRowType().getFieldCount();
final boolean outerJoin = notIn || logic == RelOptUtil.Logic.TRUE_FALSE_UNKNOWN;
if (!outerJoin) {
final LogicalAggregate aggregate = LogicalAggregate.create(ret, ImmutableBitSet.range(keyCount), null, ImmutableList.<AggregateCall>of());
return new Exists(aggregate, false, false);
}
// for IN/NOT IN, it needs to output the fields
final List<RexNode> exprs = new ArrayList<>();
if (subQueryType == SubQueryType.IN) {
for (int i = 0; i < keyCount; i++) {
exprs.add(rexBuilder.makeInputRef(ret, i));
}
}
final int projectedKeyCount = exprs.size();
exprs.add(rexBuilder.makeLiteral(true));
ret = relBuilder.push(ret).project(exprs).build();
final AggregateCall aggCall = AggregateCall.create(SqlStdOperatorTable.MIN, false, false, ImmutableList.of(projectedKeyCount), -1, projectedKeyCount, ret, null, null);
ret = LogicalAggregate.create(ret, ImmutableBitSet.range(projectedKeyCount), null, ImmutableList.of(aggCall));
switch(logic) {
case TRUE_FALSE_UNKNOWN:
case UNKNOWN_AS_TRUE:
return new Exists(ret, true, true);
default:
return new Exists(ret, false, true);
}
}
use of org.apache.beam.vendor.calcite.v1_28_0.org.apache.calcite.rel.core.AggregateCall in project calcite by apache.
the class SubstitutionVisitor method permute.
public static MutableAggregate permute(MutableAggregate aggregate, MutableRel input, Mapping mapping) {
ImmutableBitSet groupSet = Mappings.apply(mapping, aggregate.groupSet);
ImmutableList<ImmutableBitSet> groupSets = Mappings.apply2(mapping, aggregate.groupSets);
List<AggregateCall> aggregateCalls = apply(mapping, aggregate.aggCalls);
return MutableAggregate.of(input, groupSet, groupSets, aggregateCalls);
}
use of org.apache.beam.vendor.calcite.v1_28_0.org.apache.calcite.rel.core.AggregateCall in project calcite by apache.
the class SubstitutionVisitor method unifyAggregates.
public static MutableRel unifyAggregates(MutableAggregate query, MutableAggregate target) {
if (query.getGroupType() != Aggregate.Group.SIMPLE || target.getGroupType() != Aggregate.Group.SIMPLE) {
throw new AssertionError(Bug.CALCITE_461_FIXED);
}
MutableRel result;
if (query.groupSet.equals(target.groupSet)) {
// Same level of aggregation. Generate a project.
final List<Integer> projects = Lists.newArrayList();
final int groupCount = query.groupSet.cardinality();
for (int i = 0; i < groupCount; i++) {
projects.add(i);
}
for (AggregateCall aggregateCall : query.aggCalls) {
int i = target.aggCalls.indexOf(aggregateCall);
if (i < 0) {
return null;
}
projects.add(groupCount + i);
}
result = MutableRels.createProject(target, projects);
} else {
// Target is coarser level of aggregation. Generate an aggregate.
final ImmutableBitSet.Builder groupSet = ImmutableBitSet.builder();
final List<Integer> targetGroupList = target.groupSet.asList();
for (int c : query.groupSet) {
int c2 = targetGroupList.indexOf(c);
if (c2 < 0) {
return null;
}
groupSet.set(c2);
}
final List<AggregateCall> aggregateCalls = Lists.newArrayList();
for (AggregateCall aggregateCall : query.aggCalls) {
if (aggregateCall.isDistinct()) {
return null;
}
int i = target.aggCalls.indexOf(aggregateCall);
if (i < 0) {
return null;
}
aggregateCalls.add(AggregateCall.create(getRollup(aggregateCall.getAggregation()), aggregateCall.isDistinct(), aggregateCall.isApproximate(), ImmutableList.of(target.groupSet.cardinality() + i), -1, aggregateCall.type, aggregateCall.name));
}
result = MutableAggregate.of(target, groupSet.build(), null, aggregateCalls);
}
return MutableRels.createCastRel(result, query.rowType, true);
}
Aggregations