| /* |
| * 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.rel.convert; |
| |
| import org.apache.calcite.plan.Convention; |
| import org.apache.calcite.plan.RelOptRule; |
| import org.apache.calcite.plan.RelOptRuleCall; |
| import org.apache.calcite.plan.RelRule; |
| import org.apache.calcite.plan.RelTrait; |
| import org.apache.calcite.plan.RelTraitDef; |
| import org.apache.calcite.rel.RelNode; |
| import org.apache.calcite.tools.RelBuilderFactory; |
| import org.apache.calcite.util.ImmutableBeans; |
| |
| import org.checkerframework.checker.nullness.qual.Nullable; |
| import org.immutables.value.Value; |
| |
| import java.util.Locale; |
| import java.util.Objects; |
| import java.util.function.Function; |
| import java.util.function.Predicate; |
| |
| import static org.apache.calcite.linq4j.Nullness.castNonNull; |
| |
| /** |
| * Abstract base class for a rule which converts from one calling convention to |
| * another without changing semantics. |
| */ |
| @Value.Enclosing |
| public abstract class ConverterRule |
| extends RelRule<ConverterRule.Config> { |
| //~ Instance fields -------------------------------------------------------- |
| |
| private final RelTrait inTrait; |
| private final RelTrait outTrait; |
| protected final Convention out; |
| |
| //~ Constructors ----------------------------------------------------------- |
| |
| /** Creates a <code>ConverterRule</code>. */ |
| protected ConverterRule(Config config) { |
| super(config); |
| this.inTrait = Objects.requireNonNull(config.inTrait()); |
| this.outTrait = Objects.requireNonNull(config.outTrait()); |
| |
| // Source and target traits must have same type |
| assert inTrait.getTraitDef() == outTrait.getTraitDef(); |
| |
| // Most sub-classes are concerned with converting one convention to |
| // another, and for them, the "out" field is a convenient short-cut. |
| this.out = outTrait instanceof Convention ? (Convention) outTrait |
| : castNonNull(null); |
| } |
| |
| /** |
| * Creates a <code>ConverterRule</code>. |
| * |
| * @param clazz Type of relational expression to consider converting |
| * @param in Trait of relational expression to consider converting |
| * @param out Trait which is converted to |
| * @param descriptionPrefix Description prefix of rule |
| * |
| * @deprecated Use {@link #ConverterRule(Config)} |
| */ |
| @Deprecated // to be removed before 2.0 |
| protected ConverterRule(Class<? extends RelNode> clazz, RelTrait in, |
| RelTrait out, String descriptionPrefix) { |
| this(Config.INSTANCE |
| .withConversion(clazz, in, out, descriptionPrefix)); |
| } |
| |
| @SuppressWarnings("Guava") |
| @Deprecated // to be removed before 2.0 |
| protected <R extends RelNode> ConverterRule(Class<R> clazz, |
| com.google.common.base.Predicate<? super R> predicate, |
| RelTrait in, RelTrait out, String descriptionPrefix) { |
| this(Config.INSTANCE |
| .withConversion(clazz, (Predicate<? super R>) predicate::apply, |
| in, out, descriptionPrefix)); |
| } |
| |
| /** |
| * Creates a <code>ConverterRule</code> with a predicate. |
| * |
| * @param clazz Type of relational expression to consider converting |
| * @param predicate Predicate on the relational expression |
| * @param in Trait of relational expression to consider converting |
| * @param out Trait which is converted to |
| * @param relBuilderFactory Builder for relational expressions |
| * @param descriptionPrefix Description prefix of rule |
| * |
| * @deprecated Use {@link #ConverterRule(Config)} |
| */ |
| @Deprecated // to be removed before 2.0 |
| protected <R extends RelNode> ConverterRule(Class<R> clazz, |
| Predicate<? super R> predicate, RelTrait in, RelTrait out, |
| RelBuilderFactory relBuilderFactory, String descriptionPrefix) { |
| this(ImmutableConverterRule.Config.builder() |
| .withRelBuilderFactory(relBuilderFactory) |
| .build() |
| .withConversion(clazz, predicate, in, out, descriptionPrefix)); |
| } |
| |
| @SuppressWarnings("Guava") |
| @Deprecated // to be removed before 2.0 |
| protected <R extends RelNode> ConverterRule(Class<R> clazz, |
| com.google.common.base.Predicate<? super R> predicate, RelTrait in, |
| RelTrait out, RelBuilderFactory relBuilderFactory, String description) { |
| this(clazz, (Predicate<? super R>) predicate::apply, in, out, |
| relBuilderFactory, description); |
| } |
| |
| //~ Methods ---------------------------------------------------------------- |
| |
| @Override public Convention getOutConvention() { |
| return (Convention) outTrait; |
| } |
| |
| @Override public RelTrait getOutTrait() { |
| return outTrait; |
| } |
| |
| public RelTrait getInTrait() { |
| return inTrait; |
| } |
| |
| public RelTraitDef getTraitDef() { |
| return inTrait.getTraitDef(); |
| } |
| |
| private static String createDescription(String descriptionPrefix, |
| RelTrait in, RelTrait out) { |
| return String.format(Locale.ROOT, "%s(in:%s,out:%s)", |
| Objects.toString(descriptionPrefix, "ConverterRule"), in, out); |
| } |
| |
| /** Converts a relational expression to the target trait(s) of this rule. |
| * |
| * <p>Returns null if conversion is not possible. */ |
| public abstract @Nullable RelNode convert(RelNode rel); |
| |
| /** |
| * Returns true if this rule can convert <em>any</em> relational expression |
| * of the input convention. |
| * |
| * <p>The union-to-java converter, for example, is not guaranteed, because |
| * it only works on unions.</p> |
| * |
| * @return {@code true} if this rule can convert <em>any</em> relational |
| * expression |
| */ |
| public boolean isGuaranteed() { |
| return false; |
| } |
| |
| @Override public void onMatch(RelOptRuleCall call) { |
| RelNode rel = call.rel(0); |
| if (rel.getTraitSet().contains(inTrait)) { |
| final RelNode converted = convert(rel); |
| if (converted != null) { |
| call.transformTo(converted); |
| } |
| } |
| } |
| |
| //~ Inner Classes ---------------------------------------------------------- |
| |
| /** Rule configuration. */ |
| @Value.Immutable(singleton = false) |
| public interface Config extends RelRule.Config { |
| Config INSTANCE = ImmutableConverterRule.Config.builder() |
| .withInTrait(Convention.NONE) |
| .withOutTrait(Convention.NONE) |
| .withRuleFactory(new Function<Config, ConverterRule>() { |
| @Override public ConverterRule apply(final Config config) { |
| throw new UnsupportedOperationException("A rule factory must be provided"); |
| } |
| }).build(); |
| |
| @ImmutableBeans.Property |
| RelTrait inTrait(); |
| |
| /** Sets {@link #inTrait}. */ |
| Config withInTrait(RelTrait trait); |
| |
| @ImmutableBeans.Property |
| RelTrait outTrait(); |
| |
| /** Sets {@link #outTrait}. */ |
| Config withOutTrait(RelTrait trait); |
| |
| @ImmutableBeans.Property |
| Function<Config, ConverterRule> ruleFactory(); |
| |
| /** Sets {@link #outTrait}. */ |
| Config withRuleFactory(Function<Config, ConverterRule> factory); |
| |
| default <R extends RelNode> Config withConversion(Class<R> clazz, |
| Predicate<? super R> predicate, RelTrait in, RelTrait out, |
| String descriptionPrefix) { |
| return withInTrait(in) |
| .withOutTrait(out) |
| .withOperandSupplier(b -> |
| b.operand(clazz).predicate(predicate).convert(in)) |
| .withDescription(createDescription(descriptionPrefix, in, out)) |
| .as(Config.class); |
| } |
| |
| default Config withConversion(Class<? extends RelNode> clazz, RelTrait in, |
| RelTrait out, String descriptionPrefix) { |
| return withConversion(clazz, r -> true, in, out, descriptionPrefix); |
| } |
| |
| @Override default RelOptRule toRule() { |
| return toRule(ConverterRule.class); |
| } |
| |
| default <R extends ConverterRule> R toRule(Class<R> ruleClass) { |
| return ruleClass.cast(ruleFactory().apply(this)); |
| } |
| } |
| |
| } |