blob: b5a617a52a418b2f13e1d88906ddc7812a10932c [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to you under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.calcite.adapter.enumerable;
import org.apache.calcite.linq4j.Ord;
import org.apache.calcite.linq4j.tree.BlockBuilder;
import org.apache.calcite.linq4j.tree.Expression;
import org.apache.calcite.linq4j.tree.Expressions;
import org.apache.calcite.linq4j.tree.ParameterExpression;
import org.apache.calcite.plan.RelOptCluster;
import org.apache.calcite.plan.RelTraitSet;
import org.apache.calcite.rel.RelCollation;
import org.apache.calcite.rel.RelNode;
import org.apache.calcite.util.BuiltInMethod;
import org.apache.calcite.util.Pair;
import org.apache.calcite.util.Util;
import java.util.ArrayList;
import java.util.List;
/** Implementation of {@link org.apache.calcite.rel.core.Union} in
* {@link org.apache.calcite.adapter.enumerable.EnumerableConvention enumerable calling convention}.
* Performs a union (or union all) of all its inputs (which must be already sorted),
* respecting the order. */
public class EnumerableMergeUnion extends EnumerableUnion {
protected EnumerableMergeUnion(RelOptCluster cluster, RelTraitSet traitSet, List<RelNode> inputs,
boolean all) {
super(cluster, traitSet, inputs, all);
final RelCollation collation = traitSet.getCollation();
if (collation == null || collation.getFieldCollations().isEmpty()) {
throw new IllegalArgumentException("EnumerableMergeUnion with no collation");
}
for (RelNode input : inputs) {
final RelCollation inputCollation = input.getTraitSet().getCollation();
if (inputCollation == null || !inputCollation.satisfies(collation)) {
throw new IllegalArgumentException("EnumerableMergeUnion input does not satisfy collation. "
+ "EnumerableMergeUnion collation: " + collation + ". Input collation: "
+ inputCollation + ". Input: " + input);
}
}
}
public static EnumerableMergeUnion create(RelCollation collation, List<RelNode> inputs,
boolean all) {
final RelOptCluster cluster = inputs.get(0).getCluster();
final RelTraitSet traitSet = cluster.traitSetOf(EnumerableConvention.INSTANCE).replace(
collation);
return new EnumerableMergeUnion(cluster, traitSet, inputs, all);
}
@Override public EnumerableMergeUnion copy(RelTraitSet traitSet, List<RelNode> inputs,
boolean all) {
return new EnumerableMergeUnion(getCluster(), traitSet, inputs, all);
}
@Override public Result implement(EnumerableRelImplementor implementor, Prefer pref) {
final BlockBuilder builder = new BlockBuilder();
final ParameterExpression inputListExp = Expressions.parameter(
List.class,
builder.newName("mergeUnionInputs" + Integer.toUnsignedString(this.getId())));
builder.add(Expressions.declare(0, inputListExp, Expressions.new_(ArrayList.class)));
for (Ord<RelNode> ord : Ord.zip(inputs)) {
final EnumerableRel input = (EnumerableRel) ord.e;
final Result result = implementor.visitChild(this, ord.i, input, pref);
final Expression childExp = builder.append("child" + ord.i, result.block);
builder.add(
Expressions.statement(
Expressions.call(inputListExp, BuiltInMethod.COLLECTION_ADD.method, childExp)));
}
final PhysType physType = PhysTypeImpl.of(
implementor.getTypeFactory(),
getRowType(),
pref.prefer(JavaRowFormat.CUSTOM));
final RelCollation collation = getTraitSet().getCollation();
if (collation == null || collation.getFieldCollations().isEmpty()) {
// should not happen
throw new IllegalStateException("EnumerableMergeUnion with no collation");
}
final Pair<Expression, Expression> pair =
physType.generateCollationKey(collation.getFieldCollations());
final Expression sortKeySelector = pair.left;
final Expression sortComparator = pair.right;
final Expression equalityComparator = Util.first(
physType.comparer(),
Expressions.call(BuiltInMethod.IDENTITY_COMPARER.method));
final Expression unionExp = Expressions.call(
BuiltInMethod.MERGE_UNION.method,
inputListExp,
sortKeySelector,
sortComparator,
Expressions.constant(all, boolean.class),
equalityComparator);
builder.add(unionExp);
return implementor.result(physType, builder.toBlock());
}
}