com.hazelcast.org.apache.calcite.adapter.enumerable.EnumerableCalc Maven / Gradle / Ivy
/*
* 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 com.hazelcast.org.apache.calcite.adapter.enumerable;
import com.hazelcast.org.apache.calcite.DataContext;
import com.hazelcast.org.apache.calcite.adapter.java.JavaTypeFactory;
import com.hazelcast.org.apache.calcite.linq4j.Enumerator;
import com.hazelcast.org.apache.calcite.linq4j.tree.BlockBuilder;
import com.hazelcast.org.apache.calcite.linq4j.tree.BlockStatement;
import com.hazelcast.org.apache.calcite.linq4j.tree.Blocks;
import com.hazelcast.org.apache.calcite.linq4j.tree.Expression;
import com.hazelcast.org.apache.calcite.linq4j.tree.Expressions;
import com.hazelcast.org.apache.calcite.linq4j.tree.MemberDeclaration;
import com.hazelcast.org.apache.calcite.linq4j.tree.ParameterExpression;
import com.hazelcast.org.apache.calcite.linq4j.tree.Types;
import com.hazelcast.org.apache.calcite.plan.RelOptCluster;
import com.hazelcast.org.apache.calcite.plan.RelOptPredicateList;
import com.hazelcast.org.apache.calcite.plan.RelTraitSet;
import com.hazelcast.org.apache.calcite.rel.RelCollation;
import com.hazelcast.org.apache.calcite.rel.RelCollationTraitDef;
import com.hazelcast.org.apache.calcite.rel.RelDistributionTraitDef;
import com.hazelcast.org.apache.calcite.rel.RelNode;
import com.hazelcast.org.apache.calcite.rel.core.Calc;
import com.hazelcast.org.apache.calcite.rel.metadata.RelMdCollation;
import com.hazelcast.org.apache.calcite.rel.metadata.RelMdDistribution;
import com.hazelcast.org.apache.calcite.rel.metadata.RelMetadataQuery;
import com.hazelcast.org.apache.calcite.rex.RexBuilder;
import com.hazelcast.org.apache.calcite.rex.RexNode;
import com.hazelcast.org.apache.calcite.rex.RexProgram;
import com.hazelcast.org.apache.calcite.rex.RexSimplify;
import com.hazelcast.org.apache.calcite.rex.RexUtil;
import com.hazelcast.org.apache.calcite.sql.validate.SqlConformance;
import com.hazelcast.org.apache.calcite.sql.validate.SqlConformanceEnum;
import com.hazelcast.org.apache.calcite.util.BuiltInMethod;
import com.hazelcast.org.apache.calcite.util.Pair;
import com.hazelcast.org.apache.calcite.util.Util;
import com.hazelcast.com.google.common.collect.ImmutableList;
import com.hazelcast.org.checkerframework.checker.nullness.qual.Nullable;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.util.List;
import static com.hazelcast.org.apache.calcite.adapter.enumerable.EnumUtils.BRIDGE_METHODS;
import static com.hazelcast.org.apache.calcite.adapter.enumerable.EnumUtils.NO_EXPRS;
import static com.hazelcast.org.apache.calcite.adapter.enumerable.EnumUtils.NO_PARAMS;
/** Implementation of {@link com.hazelcast.org.apache.calcite.rel.core.Calc} in
* {@link com.hazelcast.org.apache.calcite.adapter.enumerable.EnumerableConvention enumerable calling convention}. */
public class EnumerableCalc extends Calc implements EnumerableRel {
/**
* Creates an EnumerableCalc.
*
* Use {@link #create} unless you know what you're doing.
*/
public EnumerableCalc(RelOptCluster cluster,
RelTraitSet traitSet,
RelNode input,
RexProgram program) {
super(cluster, traitSet, ImmutableList.of(), input, program);
assert getConvention() instanceof EnumerableConvention;
assert !program.containsAggs();
}
@Deprecated // to be removed before 2.0
public EnumerableCalc(
RelOptCluster cluster,
RelTraitSet traitSet,
RelNode input,
RexProgram program,
List collationList) {
this(cluster, traitSet, input, program);
Util.discard(collationList);
}
/** Creates an EnumerableCalc. */
public static EnumerableCalc create(final RelNode input,
final RexProgram program) {
final RelOptCluster cluster = input.getCluster();
final RelMetadataQuery mq = cluster.getMetadataQuery();
final RelTraitSet traitSet = cluster.traitSet()
.replace(EnumerableConvention.INSTANCE)
.replaceIfs(RelCollationTraitDef.INSTANCE,
() -> RelMdCollation.calc(mq, input, program))
.replaceIf(RelDistributionTraitDef.INSTANCE,
() -> RelMdDistribution.calc(mq, input, program));
return new EnumerableCalc(cluster, traitSet, input, program);
}
@Override public EnumerableCalc copy(RelTraitSet traitSet, RelNode child,
RexProgram program) {
// we do not need to copy program; it is immutable
return new EnumerableCalc(getCluster(), traitSet, child, program);
}
@Override public Result implement(EnumerableRelImplementor implementor, Prefer pref) {
final JavaTypeFactory typeFactory = implementor.getTypeFactory();
final BlockBuilder builder = new BlockBuilder();
final EnumerableRel child = (EnumerableRel) getInput();
final Result result =
implementor.visitChild(this, 0, child, pref);
final PhysType physType =
PhysTypeImpl.of(
typeFactory, getRowType(), pref.prefer(result.format));
// final Enumerable inputEnumerable = <>;
// return new Enumerable() {
// Enumerator enumerator() {
// return new Enumerator() {
// public void reset() {
// ...
Type outputJavaType = physType.getJavaRowType();
final Type enumeratorType =
Types.of(
Enumerator.class, outputJavaType);
Type inputJavaType = result.physType.getJavaRowType();
ParameterExpression inputEnumerator =
Expressions.parameter(
Types.of(
Enumerator.class, inputJavaType),
"inputEnumerator");
Expression input =
EnumUtils.convert(
Expressions.call(
inputEnumerator,
BuiltInMethod.ENUMERATOR_CURRENT.method),
inputJavaType);
final RexBuilder rexBuilder = getCluster().getRexBuilder();
final RelMetadataQuery mq = getCluster().getMetadataQuery();
final RelOptPredicateList predicates = mq.getPulledUpPredicates(child);
final RexSimplify simplify =
new RexSimplify(rexBuilder, predicates, RexUtil.EXECUTOR);
final RexProgram program = this.program.normalize(rexBuilder, simplify);
BlockStatement moveNextBody;
if (program.getCondition() == null) {
moveNextBody =
Blocks.toFunctionBlock(
Expressions.call(
inputEnumerator,
BuiltInMethod.ENUMERATOR_MOVE_NEXT.method));
} else {
final BlockBuilder builder2 = new BlockBuilder();
Expression condition =
RexToLixTranslator.translateCondition(
program,
typeFactory,
builder2,
new RexToLixTranslator.InputGetterImpl(input, result.physType),
implementor.allCorrelateVariables, implementor.getConformance());
builder2.add(
Expressions.ifThen(
condition,
Expressions.return_(
null, Expressions.constant(true))));
moveNextBody =
Expressions.block(
Expressions.while_(
Expressions.call(
inputEnumerator,
BuiltInMethod.ENUMERATOR_MOVE_NEXT.method),
builder2.toBlock()),
Expressions.return_(
null,
Expressions.constant(false)));
}
final BlockBuilder builder3 = new BlockBuilder();
final SqlConformance conformance =
(SqlConformance) implementor.map.getOrDefault("_conformance",
SqlConformanceEnum.DEFAULT);
List expressions =
RexToLixTranslator.translateProjects(
program,
typeFactory,
conformance,
builder3,
null,
physType,
DataContext.ROOT,
new RexToLixTranslator.InputGetterImpl(input, result.physType),
implementor.allCorrelateVariables);
builder3.add(
Expressions.return_(
null, physType.record(expressions)));
BlockStatement currentBody =
builder3.toBlock();
final Expression inputEnumerable =
builder.append(
"inputEnumerable", result.block, false);
final Expression body =
Expressions.new_(
enumeratorType,
NO_EXPRS,
Expressions.list(
Expressions.fieldDecl(
Modifier.PUBLIC
| Modifier.FINAL,
inputEnumerator,
Expressions.call(
inputEnumerable,
BuiltInMethod.ENUMERABLE_ENUMERATOR.method)),
EnumUtils.overridingMethodDecl(
BuiltInMethod.ENUMERATOR_RESET.method,
NO_PARAMS,
Blocks.toFunctionBlock(
Expressions.call(
inputEnumerator,
BuiltInMethod.ENUMERATOR_RESET.method))),
EnumUtils.overridingMethodDecl(
BuiltInMethod.ENUMERATOR_MOVE_NEXT.method,
NO_PARAMS,
moveNextBody),
EnumUtils.overridingMethodDecl(
BuiltInMethod.ENUMERATOR_CLOSE.method,
NO_PARAMS,
Blocks.toFunctionBlock(
Expressions.call(
inputEnumerator,
BuiltInMethod.ENUMERATOR_CLOSE.method))),
Expressions.methodDecl(
Modifier.PUBLIC,
BRIDGE_METHODS
? Object.class
: outputJavaType,
"current",
NO_PARAMS,
currentBody)));
builder.add(
Expressions.return_(
null,
Expressions.new_(
BuiltInMethod.ABSTRACT_ENUMERABLE_CTOR.constructor,
// TODO: generics
// Collections.singletonList(inputRowType),
NO_EXPRS,
ImmutableList.of(
Expressions.methodDecl(
Modifier.PUBLIC,
enumeratorType,
BuiltInMethod.ENUMERABLE_ENUMERATOR.method.getName(),
NO_PARAMS,
Blocks.toFunctionBlock(body))))));
return implementor.result(physType, builder.toBlock());
}
@Override public @Nullable Pair> passThroughTraits(
final RelTraitSet required) {
final List exps = Util.transform(program.getProjectList(),
program::expandLocalRef);
return EnumerableTraitsUtils.passThroughTraitsForProject(required, exps,
input.getRowType(), input.getCluster().getTypeFactory(), traitSet);
}
@Override public @Nullable Pair> deriveTraits(
final RelTraitSet childTraits, final int childId) {
final List exps = Util.transform(program.getProjectList(),
program::expandLocalRef);
return EnumerableTraitsUtils.deriveTraitsForProject(childTraits, childId, exps,
input.getRowType(), input.getCluster().getTypeFactory(), traitSet);
}
@Override public RexProgram getProgram() {
return program;
}
}