content: /*
   * 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.plan.volcano;
  
  import org.apache.calcite.plan.RelOptCluster;
  import org.apache.calcite.plan.RelOptCost;
  import org.apache.calcite.plan.RelOptPlanner;
  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.plan.RelTraitSet;
  import org.apache.calcite.rel.RelNode;
  import org.apache.calcite.rel.RelWriter;
  import org.apache.calcite.rel.convert.ConverterImpl;
  import org.apache.calcite.rel.metadata.RelMetadataQuery;
  import org.apache.calcite.tools.RelBuilderFactory;
  
  import org.checkerframework.checker.nullness.qual.Nullable;
  import org.immutables.value.Value;
  
  import java.util.List;
  
  /**
   * Converts a relational expression to any given output convention.
   *
   * <p>Unlike most {@link org.apache.calcite.rel.convert.Converter}s, an abstract
   * converter is always abstract. You would typically create an
   * <code>AbstractConverter</code> when it is necessary to transform a relational
   * expression immediately; later, rules will transform it into relational
   * expressions which can be implemented.
   *
   * <p>If an abstract converter cannot be satisfied immediately (because the
   * source subset is abstract), the set is flagged, so this converter will be
   * expanded as soon as a non-abstract relexp is added to the set.
   */
  @Value.Enclosing
  public class AbstractConverter extends ConverterImpl {
    //~ Constructors -----------------------------------------------------------
  
    public AbstractConverter(
        RelOptCluster cluster,
        RelSubset rel,
        @Nullable RelTraitDef traitDef,
        RelTraitSet traits) {
      super(cluster, traitDef, traits, rel);
      assert traits.allSimple();
    }
  
    //~ Methods ----------------------------------------------------------------
  
  
    @Override public RelNode copy(RelTraitSet traitSet, List<RelNode> inputs) {
      return new AbstractConverter(
          getCluster(),
          (RelSubset) sole(inputs),
          traitDef,
          traitSet);
    }
  
    @Override public @Nullable RelOptCost computeSelfCost(RelOptPlanner planner,
        RelMetadataQuery mq) {
      return planner.getCostFactory().makeInfiniteCost();
    }
  
    @Override public RelWriter explainTerms(RelWriter pw) {
      super.explainTerms(pw);
      for (RelTrait trait : traitSet) {
        pw.item(trait.getTraitDef().getSimpleName(), trait);
      }
      return pw;
    }
  
    @Override public boolean isEnforcer() {
      return true;
    }
  
    //~ Inner Classes ----------------------------------------------------------
  
    /**
     * Rule that converts an {@link AbstractConverter} into a chain of
     * converters from the source relation to the target traits.
     *
     * <p>The chain produced is minimal: we have previously built the transitive
     * closure of the graph of conversions, so we choose the shortest chain.
     *
     * <p>Unlike the {@link AbstractConverter} they are replacing, these
     * converters are guaranteed to be able to convert any relation of their
     * calling convention. Furthermore, because they introduce subsets of other
     * calling conventions along the way, these subsets may spawn more efficient
     * conversions which are not generally applicable.
     *
     * <p>AbstractConverters can be messy, so they restrain themselves: they
     * don't fire if the target subset already has an implementation (with less
     * than infinite cost).
     */
    public static class ExpandConversionRule
        extends RelRule<ExpandConversionRule.Config> {
      public static final ExpandConversionRule INSTANCE =
          Config.DEFAULT.toRule();
  
      /** Creates an ExpandConversionRule. */
      protected ExpandConversionRule(Config config) {
        super(config);
      }
  
      @Deprecated // to be removed before 2.0
      public ExpandConversionRule(RelBuilderFactory relBuilderFactory) {
        this(Config.DEFAULT.withRelBuilderFactory(relBuilderFactory)
            .as(Config.class));
      }
  
      @Override public void onMatch(RelOptRuleCall call) {
        final VolcanoPlanner planner = (VolcanoPlanner) call.getPlanner();
        AbstractConverter converter = call.rel(0);
        final RelNode child = converter.getInput();
        RelNode converted =
            planner.changeTraitsUsingConverters(
                child,
                converter.traitSet);
        if (converted != null) {
          call.transformTo(converted);
        }
      }
  
      /** Rule configuration. */
      @Value.Immutable
      public interface Config extends RelRule.Config {
        Config DEFAULT = ImmutableConverter.Config.of()
            .withOperandSupplier(b ->
                b.operand(AbstractConverter.class).anyInputs());
  
        @Override default ExpandConversionRule toRule() {
          return new ExpandConversionRule(this);
        }
      }
    }
  }
  