CoreRules.java

/*
 * 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.rules;

import org.apache.calcite.linq4j.function.Experimental;
import org.apache.calcite.plan.RelOptUtil.Exists;
import org.apache.calcite.rel.RelNode;
import org.apache.calcite.rel.core.Aggregate;
import org.apache.calcite.rel.core.Calc;
import org.apache.calcite.rel.core.Correlate;
import org.apache.calcite.rel.core.Filter;
import org.apache.calcite.rel.core.Intersect;
import org.apache.calcite.rel.core.Join;
import org.apache.calcite.rel.core.Minus;
import org.apache.calcite.rel.core.Project;
import org.apache.calcite.rel.core.Sample;
import org.apache.calcite.rel.core.SetOp;
import org.apache.calcite.rel.core.Sort;
import org.apache.calcite.rel.core.TableFunctionScan;
import org.apache.calcite.rel.core.TableScan;
import org.apache.calcite.rel.core.Union;
import org.apache.calcite.rel.core.Values;
import org.apache.calcite.rel.logical.LogicalAggregate;
import org.apache.calcite.rel.logical.LogicalCalc;
import org.apache.calcite.rel.logical.LogicalCorrelate;
import org.apache.calcite.rel.logical.LogicalExchange;
import org.apache.calcite.rel.logical.LogicalFilter;
import org.apache.calcite.rel.logical.LogicalJoin;
import org.apache.calcite.rel.logical.LogicalMatch;
import org.apache.calcite.rel.logical.LogicalProject;
import org.apache.calcite.rel.logical.LogicalSortExchange;
import org.apache.calcite.rel.logical.LogicalWindow;
import org.apache.calcite.rel.rules.FilterJoinRule.FilterIntoJoinRule.FilterIntoJoinRuleConfig;
import org.apache.calcite.rel.rules.FilterTableFunctionTransposeRule.Config;
import org.apache.calcite.rel.rules.materialize.MaterializedViewRules;
import org.apache.calcite.rex.RexInputRef;
import org.apache.calcite.rex.RexUtil;
import org.apache.calcite.schema.impl.StarTable;

/** Rules that perform logical transformations on relational expressions.
 *
 * @see MaterializedViewRules */
public class CoreRules {

  private CoreRules() {}

  /** Rule that recognizes an {@link Aggregate}
   * on top of a {@link Project} and if possible
   * aggregates through the Project or removes the Project. */
  public static final AggregateProjectMergeRule AGGREGATE_PROJECT_MERGE =
      AggregateProjectMergeRule.Config.DEFAULT.toRule();

  /** Rule that removes constant keys from an {@link Aggregate}. */
  public static final AggregateProjectPullUpConstantsRule
      AGGREGATE_PROJECT_PULL_UP_CONSTANTS =
      AggregateProjectPullUpConstantsRule.Config.DEFAULT.toRule();

  /** More general form of {@link #AGGREGATE_PROJECT_PULL_UP_CONSTANTS}
   * that matches any relational expression. */
  public static final AggregateProjectPullUpConstantsRule
      AGGREGATE_ANY_PULL_UP_CONSTANTS =
      AggregateProjectPullUpConstantsRule.Config.ANY.toRule();

  /** Rule that matches an {@link Aggregate} on
   * a {@link StarTable.StarTableScan}. */
  public static final AggregateStarTableRule AGGREGATE_STAR_TABLE =
      AggregateStarTableRule.Config.DEFAULT.toRule();

  /** Variant of {@link #AGGREGATE_STAR_TABLE} that accepts a {@link Project}
   * between the {@link Aggregate} and its {@link StarTable.StarTableScan}
   * input. */
  public static final AggregateProjectStarTableRule AGGREGATE_PROJECT_STAR_TABLE =
      AggregateProjectStarTableRule.Config.DEFAULT.toRule();

  /** Rule that reduces aggregate functions in
   * an {@link Aggregate} to simpler forms. */
  public static final AggregateReduceFunctionsRule AGGREGATE_REDUCE_FUNCTIONS =
      AggregateReduceFunctionsRule.Config.DEFAULT.toRule();

  /** Rule that matches an {@link Aggregate} on an {@link Aggregate},
   * and merges into a single Aggregate if the top aggregate's group key is a
   * subset of the lower aggregate's group key, and the aggregates are
   * expansions of rollups. */
  public static final AggregateMergeRule AGGREGATE_MERGE =
      AggregateMergeRule.Config.DEFAULT.toRule();

  /** Rule that removes an {@link Aggregate}
   * if it computes no aggregate functions
   * (that is, it is implementing {@code SELECT DISTINCT}),
   * or all the aggregate functions are splittable,
   * and the underlying relational expression is already distinct. */
  public static final AggregateRemoveRule AGGREGATE_REMOVE =
      AggregateRemoveRule.Config.DEFAULT.toRule();

  /** Rule that transforms an MIN/MAX {@link Aggregate} functions
   * into equivalent subqueries with ORDER BY and LIMIT 1. */
  public static final AggregateMinMaxToLimitRule AGGREGATE_MIN_MAX_TO_LIMIT =
      AggregateMinMaxToLimitRule.Config.DEFAULT.toRule();

  /** Rule that expands distinct aggregates
   * (such as {@code COUNT(DISTINCT x)}) from a
   * {@link Aggregate}.
   * This instance operates only on logical expressions. */
  public static final AggregateExpandDistinctAggregatesRule
      AGGREGATE_EXPAND_DISTINCT_AGGREGATES =
      AggregateExpandDistinctAggregatesRule.Config.DEFAULT.toRule();

  /** As {@link #AGGREGATE_EXPAND_DISTINCT_AGGREGATES} but generates a Join. */
  public static final AggregateExpandDistinctAggregatesRule
      AGGREGATE_EXPAND_DISTINCT_AGGREGATES_TO_JOIN =
      AggregateExpandDistinctAggregatesRule.Config.JOIN.toRule();

  /** Rule that rewrites a {@link LogicalAggregate} that contains
   * {@code WITHIN DISTINCT} aggregate functions to one that does not. */
  public static final AggregateExpandWithinDistinctRule
      AGGREGATE_EXPAND_WITHIN_DISTINCT =
      AggregateExpandWithinDistinctRule.Config.DEFAULT.toRule();

  /** Rule that matches an {@link Aggregate}
   * on a {@link Filter} and transposes them,
   * pushing the aggregate below the filter. */
  public static final AggregateFilterTransposeRule AGGREGATE_FILTER_TRANSPOSE =
      AggregateFilterTransposeRule.Config.DEFAULT.toRule();

  /** Rule that matches an {@link Aggregate}
   * on a {@link Join} and removes the left input
   * of the join provided that the left input is also a left join if
   * possible. */
  public static final AggregateJoinJoinRemoveRule AGGREGATE_JOIN_JOIN_REMOVE =
      AggregateJoinJoinRemoveRule.Config.DEFAULT.toRule();

  /** Rule that matches an {@link Aggregate}
   * on a {@link Join} and removes the join
   * provided that the join is a left join or right join and it computes no
   * aggregate functions or all the aggregate calls have distinct. */
  public static final AggregateJoinRemoveRule AGGREGATE_JOIN_REMOVE =
      AggregateJoinRemoveRule.Config.DEFAULT.toRule();

  /** Rule that pushes an {@link Aggregate}
   * past a {@link Join}. */
  public static final AggregateJoinTransposeRule AGGREGATE_JOIN_TRANSPOSE =
      AggregateJoinTransposeRule.Config.DEFAULT.toRule();

  /** As {@link #AGGREGATE_JOIN_TRANSPOSE}, but extended to push down aggregate
   * functions. */
  public static final AggregateJoinTransposeRule AGGREGATE_JOIN_TRANSPOSE_EXTENDED =
      AggregateJoinTransposeRule.Config.EXTENDED.toRule();

  /** Rule that pushes an {@link Aggregate}
   * past a non-distinct {@link Union}. */
  public static final AggregateUnionTransposeRule AGGREGATE_UNION_TRANSPOSE =
      AggregateUnionTransposeRule.Config.DEFAULT.toRule();

  /** Rule that matches an {@link Aggregate} whose input is a {@link Union}
   * one of whose inputs is an {@code Aggregate}.
   *
   * <p>Because it matches {@link RelNode} for each input of {@code Union}, it
   * will create O(N ^ 2) matches, which may cost too much during the popMatch
   * phase in VolcanoPlanner. If efficiency is a concern, we recommend that you
   * use {@link #AGGREGATE_UNION_AGGREGATE_FIRST}
   * and {@link #AGGREGATE_UNION_AGGREGATE_SECOND} instead. */
  public static final AggregateUnionAggregateRule AGGREGATE_UNION_AGGREGATE =
      AggregateUnionAggregateRule.Config.DEFAULT.toRule();

  /** As {@link #AGGREGATE_UNION_AGGREGATE}, but matches an {@code Aggregate}
   * only as the left input of the {@code Union}. */
  public static final AggregateUnionAggregateRule AGGREGATE_UNION_AGGREGATE_FIRST =
      AggregateUnionAggregateRule.Config.AGG_FIRST.toRule();

  /** As {@link #AGGREGATE_UNION_AGGREGATE}, but matches an {@code Aggregate}
   * only as the right input of the {@code Union}. */
  public static final AggregateUnionAggregateRule AGGREGATE_UNION_AGGREGATE_SECOND =
      AggregateUnionAggregateRule.Config.AGG_SECOND.toRule();

  /** Rule that converts CASE-style filtered aggregates into true filtered
   * aggregates. */
  public static final AggregateCaseToFilterRule AGGREGATE_CASE_TO_FILTER =
      AggregateCaseToFilterRule.Config.DEFAULT.toRule();

  /** Rule that merges a {@link Calc} onto a {@code Calc}. */
  public static final CalcMergeRule CALC_MERGE =
      CalcMergeRule.Config.DEFAULT.toRule();

  /** Rule that removes a trivial {@link LogicalCalc}. */
  public static final CalcRemoveRule CALC_REMOVE =
      CalcRemoveRule.Config.DEFAULT.toRule();

  /** Rule that reduces operations on the DECIMAL type, such as casts or
   * arithmetic, into operations involving more primitive types such as BIGINT
   * and DOUBLE. */
  public static final ReduceDecimalsRule CALC_REDUCE_DECIMALS =
      ReduceDecimalsRule.Config.DEFAULT.toRule();

  /** Rule that reduces constants inside a {@link LogicalCalc}.
   *
   * @see #FILTER_REDUCE_EXPRESSIONS */
  public static final ReduceExpressionsRule.CalcReduceExpressionsRule
      CALC_REDUCE_EXPRESSIONS =
      ReduceExpressionsRule.CalcReduceExpressionsRule.CalcReduceExpressionsRuleConfig.DEFAULT
          .toRule();

  /** Rule that converts a {@link Calc} to a {@link Project} and
   * {@link Filter}. */
  public static final CalcSplitRule CALC_SPLIT =
      CalcSplitRule.Config.DEFAULT.toRule();

  /** Rule that transforms a {@link Calc}
   * that contains windowed aggregates to a mixture of
   * {@link LogicalWindow} and {@code Calc}. */
  public static final ProjectToWindowRule.CalcToWindowRule CALC_TO_WINDOW =
      ProjectToWindowRule.CalcToWindowRule.CalcToWindowRuleConfig.DEFAULT.toRule();

  /** Rule that pre-casts inputs to a particular type. This can assist operator
   * implementations that impose requirements on their input types. */
  public static final CoerceInputsRule COERCE_INPUTS =
      CoerceInputsRule.Config.DEFAULT.toRule();

  /** Rule that removes constants inside a {@link LogicalExchange}. */
  public static final ExchangeRemoveConstantKeysRule EXCHANGE_REMOVE_CONSTANT_KEYS =
      ExchangeRemoveConstantKeysRule.Config.DEFAULT.toRule();

  /** Rule that removes constants inside a {@link LogicalSortExchange}. */
  public static final ExchangeRemoveConstantKeysRule SORT_EXCHANGE_REMOVE_CONSTANT_KEYS =
      ExchangeRemoveConstantKeysRule.Config.SORT.toRule();

  /** Rule that tries to push filter expressions into a join
   * condition and into the inputs of the join. */
  public static final FilterJoinRule.FilterIntoJoinRule FILTER_INTO_JOIN =
      FilterJoinRule.FilterIntoJoinRule.FilterIntoJoinRuleConfig.DEFAULT.toRule();

  /** Dumber version of {@link #FILTER_INTO_JOIN}. Not intended for production
   * use, but keeps some tests working for which {@code FILTER_INTO_JOIN} is too
   * smart. */
  public static final FilterJoinRule.FilterIntoJoinRule FILTER_INTO_JOIN_DUMB =
      FilterIntoJoinRuleConfig.SMART_FALSE.toRule();

  /** Rule that combines two {@link LogicalFilter}s. */
  public static final FilterMergeRule FILTER_MERGE =
      FilterMergeRule.Config.DEFAULT.toRule();

  /** Rule that merges a {@link Filter} and a {@link LogicalCalc}. The
   * result is a {@link LogicalCalc} whose filter condition is the logical AND
   * of the two.
   *
   * @see #PROJECT_CALC_MERGE */
  public static final FilterCalcMergeRule FILTER_CALC_MERGE =
      FilterCalcMergeRule.Config.DEFAULT.toRule();

  /** Rule that converts a {@link LogicalFilter} to a {@link LogicalCalc}.
   *
   * @see #PROJECT_TO_CALC */
  public static final FilterToCalcRule FILTER_TO_CALC =
      FilterToCalcRule.Config.DEFAULT.toRule();

  /** Rule that pushes a {@link Filter} past an {@link Aggregate}.
   *
   * @see #AGGREGATE_FILTER_TRANSPOSE */
  public static final FilterAggregateTransposeRule FILTER_AGGREGATE_TRANSPOSE =
      FilterAggregateTransposeRule.Config.DEFAULT.toRule();

  /** The default instance of
   * {@link org.apache.calcite.rel.rules.FilterProjectTransposeRule}.
   *
   * <p>It does not allow a Filter to be pushed past the Project if
   * {@link RexUtil#containsCorrelation there is a correlation condition}
   * anywhere in the Filter, since in some cases it can prevent a
   * {@link Correlate} from being de-correlated.
   */
  public static final FilterProjectTransposeRule FILTER_PROJECT_TRANSPOSE =
      FilterProjectTransposeRule.Config.DEFAULT.toRule();

  /** Rule that pushes a {@link Filter} past a {@link Sample}. */
  public static final FilterSampleTransposeRule FILTER_SAMPLE_TRANSPOSE =
      FilterSampleTransposeRule.Config.DEFAULT.toRule();

  /** Rule that pushes a {@link Filter}
   * past a {@link TableFunctionScan}. */
  public static final FilterTableFunctionTransposeRule
      FILTER_TABLE_FUNCTION_TRANSPOSE = Config.DEFAULT.toRule();

  /** Rule that matches a {@link Filter} on a {@link TableScan}. */
  public static final FilterTableScanRule FILTER_SCAN =
      FilterTableScanRule.Config.DEFAULT.toRule();

  /** Rule that transforms a {@link Filter} on top of a {@link Sort}
   * into a {@link Sort} on top of a {@link Filter}. */
  public static final FilterSortTransposeRule FILTER_SORT_TRANSPOSE =
          FilterSortTransposeRule.Config.DEFAULT.toRule();

  /** Rule that matches a {@link Filter} on an
   * {@link org.apache.calcite.adapter.enumerable.EnumerableInterpreter} on a
   * {@link TableScan}. */
  public static final FilterTableScanRule FILTER_INTERPRETER_SCAN =
      FilterTableScanRule.Config.INTERPRETER.toRule();

  /** Rule that pushes a {@link Filter} above a {@link Correlate} into the
   * inputs of the {@code Correlate}. */
  public static final FilterCorrelateRule FILTER_CORRELATE =
      FilterCorrelateRule.Config.DEFAULT.toRule();

  /** Rule that merges a {@link Filter} into a {@link MultiJoin},
   * creating a richer {@code MultiJoin}.
   *
   * @see #PROJECT_MULTI_JOIN_MERGE */
  public static final FilterMultiJoinMergeRule FILTER_MULTI_JOIN_MERGE =
      FilterMultiJoinMergeRule.Config.DEFAULT.toRule();

  /** Rule that replaces {@code IS NOT DISTINCT FROM}
   * in a {@link Filter} with logically equivalent operations. */
  public static final FilterRemoveIsNotDistinctFromRule
      FILTER_EXPAND_IS_NOT_DISTINCT_FROM =
      FilterRemoveIsNotDistinctFromRule.Config.DEFAULT.toRule();

  /** Rule that replaces {@code IS NOT DISTINCT FROM}
   * in a {@link Join} condition with logically equivalent operations. */
  public static final JoinConditionExpandIsNotDistinctFromRule
      JOIN_CONDITION_EXPAND_IS_NOT_DISTINCT_FROM =
      JoinConditionExpandIsNotDistinctFromRule.Config.DEFAULT.toRule();

  /** Rule that pushes a {@link Filter} past a {@link SetOp}. */
  public static final FilterSetOpTransposeRule FILTER_SET_OP_TRANSPOSE =
      FilterSetOpTransposeRule.Config.DEFAULT.toRule();

  /** Rule that pushes a {@link Filter} past a {@link org.apache.calcite.rel.core.Window}. */
  public static final FilterWindowTransposeRule FILTER_WINDOW_TRANSPOSE =
      FilterWindowTransposeRule.Config.DEFAULT.toRule();

  /** Rule that reduces constants inside a {@link LogicalFilter}.
   *
   * @see #JOIN_REDUCE_EXPRESSIONS
   * @see #PROJECT_REDUCE_EXPRESSIONS
   * @see #CALC_REDUCE_EXPRESSIONS
   * @see #WINDOW_REDUCE_EXPRESSIONS
   */
  public static final ReduceExpressionsRule.FilterReduceExpressionsRule
      FILTER_REDUCE_EXPRESSIONS =
      ReduceExpressionsRule.FilterReduceExpressionsRule.FilterReduceExpressionsRuleConfig.DEFAULT
          .toRule();

  /** Rule that flattens an {@link Intersect} on an {@code Intersect}
   * into a single {@code Intersect}. */
  public static final UnionMergeRule INTERSECT_MERGE =
      UnionMergeRule.Config.INTERSECT.toRule();

  /** Rule that removes a {@link Intersect} if it has only one input.
   *
   * @see PruneEmptyRules#UNION_INSTANCE */
  public static final UnionEliminatorRule INTERSECT_REMOVE =
      UnionEliminatorRule.Config.INTERSECT.toRule();

  /** Planner rule that reorders inputs of an {@link Intersect} to put smaller inputs first.
   * This helps reduce the size of intermediate results. */
  public static final IntersectReorderRule INTERSECT_REORDER =
      IntersectReorderRule.Config.DEFAULT.toRule();

  /** Rule that translates a distinct {@link Intersect} into a group of operators
   * composed of {@link Union}, {@link Aggregate}, etc. The rule also applies a
   * partial aggregation pushdown into the union branches. */
  public static final IntersectToDistinctRule INTERSECT_TO_DISTINCT =
      IntersectToDistinctRule.Config.DEFAULT.toRule();

  /** As {@link #INTERSECT_TO_DISTINCT} but not applying (partial) aggregate pushdown
   * into the union branches (behaviour introduced in CALCITE-6893). */
  public static final IntersectToDistinctRule INTERSECT_TO_DISTINCT_NO_AGGREGATE_PUSHDOWN =
      IntersectToDistinctRule.Config.NO_AGGREGATE_PUSHDOWN.toRule();

  /** Rule that translates a {@link Intersect}
   * into a {@link Exists} subquery. */
  public static final IntersectToExistsRule INTERSECT_TO_EXISTS =
      IntersectToExistsRule.Config.DEFAULT.toRule();

  /** Rule to translates a {@link Intersect} to {@link Join#isSemiJoin semi-join}. */
  public static final IntersectToSemiJoinRule INTERSECT_TO_SEMI_JOIN =
          IntersectToSemiJoinRule.Config.DEFAULT.toRule();

  /** Rule that translates a {@link Union} to {@link Filter}. */
  public static final SetOpToFilterRule UNION_FILTER_TO_FILTER =
      SetOpToFilterRule.Config.UNION.toRule();

  /** Rule that translates a {@link Intersect} to {@link Filter}. */
  public static final SetOpToFilterRule INTERSECT_FILTER_TO_FILTER =
      SetOpToFilterRule.Config.INTERSECT.toRule();

  /** Rule that translates a {@link Minus} to {@link Filter}. */
  public static final SetOpToFilterRule MINUS_FILTER_TO_FILTER =
      SetOpToFilterRule.Config.MINUS.toRule();

  /** Rule that sames as {@link CoreRules#MINUS_FILTER_TO_FILTER},
   * But it is deprecated. */
  @Deprecated
  public static final MinusToFilterRule MINUS_TO_FILTER =
      MinusToFilterRule.Config.DEFAULT.toRule();

  /** Rule that translates a distinct
   * {@link Minus} into a group of operators
   * composed of {@link Union}, {@link Aggregate}, etc. */
  public static final MinusToDistinctRule MINUS_TO_DISTINCT =
      MinusToDistinctRule.Config.DEFAULT.toRule();

  /** Rule to translates a {@link Minus} to {@link Join} anti-join}. */
  public static final MinusToAntiJoinRule MINUS_TO_ANTI_JOIN =
      MinusToAntiJoinRule.Config.DEFAULT.toRule();

  /** Rule that converts a {@link LogicalMatch} to the result of calling
   * {@link LogicalMatch#copy}. */
  public static final MatchRule MATCH = MatchRule.Config.DEFAULT.toRule();

  /** Rule that flattens a {@link Minus} on a {@code Minus}
   * into a single {@code Minus}. */
  public static final UnionMergeRule MINUS_MERGE =
      UnionMergeRule.Config.MINUS.toRule();

  /** Rule that removes a {@link Minus} if it has only one input.
   *
   * @see PruneEmptyRules#UNION_INSTANCE */
  public static final UnionEliminatorRule MINUS_REMOVE =
      UnionEliminatorRule.Config.MINUS.toRule();

  /** Rule that matches a {@link Project} on an {@link Aggregate},
   * projecting away aggregate calls that are not used. */
  public static final ProjectAggregateMergeRule PROJECT_AGGREGATE_MERGE =
      ProjectAggregateMergeRule.Config.DEFAULT.toRule();

  /** Rule that merges a {@link LogicalProject} and a {@link LogicalCalc}.
   *
   * @see #FILTER_CALC_MERGE */
  public static final ProjectCalcMergeRule PROJECT_CALC_MERGE =
      ProjectCalcMergeRule.Config.DEFAULT.toRule();

  /** Rule that matches a {@link Project} on a {@link Correlate} and
   * pushes the projections to the Correlate's left and right inputs. */
  public static final ProjectCorrelateTransposeRule PROJECT_CORRELATE_TRANSPOSE =
      ProjectCorrelateTransposeRule.Config.DEFAULT.toRule();

  /** Rule that pushes a {@link Project} past a {@link Filter}.
   *
   * @see #PROJECT_FILTER_TRANSPOSE_WHOLE_PROJECT_EXPRESSIONS
   * @see #PROJECT_FILTER_TRANSPOSE_WHOLE_EXPRESSIONS */
  public static final ProjectFilterTransposeRule PROJECT_FILTER_TRANSPOSE =
      ProjectFilterTransposeRule.Config.DEFAULT.toRule();

  /** As {@link #PROJECT_FILTER_TRANSPOSE}, but pushes down project and filter
   * expressions whole, not field references. */
  public static final ProjectFilterTransposeRule
      PROJECT_FILTER_TRANSPOSE_WHOLE_EXPRESSIONS =
      ProjectFilterTransposeRule.Config.PROJECT_FILTER.toRule();

  /** As {@link #PROJECT_FILTER_TRANSPOSE},
   * pushes down field references for filters,
   * but pushes down project expressions whole. */
  public static final ProjectFilterTransposeRule
      PROJECT_FILTER_TRANSPOSE_WHOLE_PROJECT_EXPRESSIONS =
      ProjectFilterTransposeRule.Config.PROJECT.toRule();

  /** Rule that reduces constants inside a {@link LogicalProject}.
   *
   * @see #FILTER_REDUCE_EXPRESSIONS */
  public static final ReduceExpressionsRule.ProjectReduceExpressionsRule
      PROJECT_REDUCE_EXPRESSIONS =
      ReduceExpressionsRule.ProjectReduceExpressionsRule.ProjectReduceExpressionsRuleConfig
          .DEFAULT.toRule();

  /** Rule that converts sub-queries from project expressions into
   * {@link Correlate} instances.
   *
   * @see #FILTER_SUB_QUERY_TO_CORRELATE
   * @see #JOIN_SUB_QUERY_TO_CORRELATE */
  public static final SubQueryRemoveRule PROJECT_SUB_QUERY_TO_CORRELATE =
      SubQueryRemoveRule.Config.PROJECT.toRule();

  /** Rule that converts a sub-queries from filter expressions into
   * {@link Correlate} instances.
   *
   * @see #PROJECT_SUB_QUERY_TO_CORRELATE
   * @see #JOIN_SUB_QUERY_TO_CORRELATE */
  public static final SubQueryRemoveRule FILTER_SUB_QUERY_TO_CORRELATE =
      SubQueryRemoveRule.Config.FILTER.toRule();

  /** Rule that converts sub-queries from join expressions into
   * {@link Correlate} instances.
   *
   * @see #PROJECT_SUB_QUERY_TO_CORRELATE
   * @see #FILTER_SUB_QUERY_TO_CORRELATE */
  public static final SubQueryRemoveRule JOIN_SUB_QUERY_TO_CORRELATE =
      SubQueryRemoveRule.Config.JOIN.toRule();

  /** Rule that converts SUM to SUM0 in OVER clauses in a project list. */
  public static final ProjectOverSumToSum0Rule PROJECT_OVER_SUM_TO_SUM0_RULE =
      ProjectOverSumToSum0Rule.Config.DEFAULT.toRule();

  /** Rule that transforms a {@link Project}
   * into a mixture of {@code LogicalProject}
   * and {@link LogicalWindow}. */
  public static final ProjectToWindowRule.ProjectToLogicalProjectAndWindowRule
      PROJECT_TO_LOGICAL_PROJECT_AND_WINDOW =
      ProjectToWindowRule.ProjectToLogicalProjectAndWindowRule.
          ProjectToLogicalProjectAndWindowRuleConfig.DEFAULT.toRule();

  /** Rule that creates a {@link Join#isSemiJoin semi-join} from a
   * {@link Project} on top of a {@link Join} with an {@link Aggregate} as its
   * right input.
   *
   * @see #JOIN_TO_SEMI_JOIN */
  public static final SemiJoinRule.ProjectToSemiJoinRule PROJECT_TO_SEMI_JOIN =
      SemiJoinRule.ProjectToSemiJoinRule.ProjectToSemiJoinRuleConfig.DEFAULT.toRule();

  /** Rule that matches an {@link Project} on a {@link Join} and removes the
   * left input of the join provided that the left input is also a left join. */
  public static final ProjectJoinJoinRemoveRule PROJECT_JOIN_JOIN_REMOVE =
      ProjectJoinJoinRemoveRule.Config.DEFAULT.toRule();

  /** Rule that matches an {@link Project} on a {@link Join} and removes the
   * join provided that the join is a left join or right join and the join keys
   * are unique. */
  public static final ProjectJoinRemoveRule PROJECT_JOIN_REMOVE =
      ProjectJoinRemoveRule.Config.DEFAULT.toRule();

  /** Rule that pushes a {@link LogicalProject} past a {@link LogicalJoin}
   * by splitting the projection into a projection on top of each child of
   * the join. */
  public static final ProjectJoinTransposeRule PROJECT_JOIN_TRANSPOSE =
      ProjectJoinTransposeRule.Config.DEFAULT.toRule();

  /** Rule that merges a {@link Project} into another {@link Project},
   * provided the projects are not projecting identical sets of input
   * references. */
  public static final ProjectMergeRule PROJECT_MERGE =
      ProjectMergeRule.Config.DEFAULT.toRule();

  /** Rule that pushes a {@link LogicalProject} past a {@link SetOp}.
   *
   * <p>The children of the {@code SetOp} will project
   * only the {@link RexInputRef}s referenced in the original
   * {@code LogicalProject}. */
  public static final ProjectSetOpTransposeRule PROJECT_SET_OP_TRANSPOSE =
      ProjectSetOpTransposeRule.Config.DEFAULT.toRule();

  /** Rule that pushes a {@link Project} into a {@link MultiJoin},
   * creating a richer {@code MultiJoin}.
   *
   * @see #FILTER_MULTI_JOIN_MERGE */
  public static final ProjectMultiJoinMergeRule PROJECT_MULTI_JOIN_MERGE =
      ProjectMultiJoinMergeRule.Config.DEFAULT.toRule();

  /** Rule that, given a {@link Project} node that merely returns its input,
   * converts the node into its input. */
  public static final ProjectRemoveRule PROJECT_REMOVE =
      ProjectRemoveRule.Config.DEFAULT.toRule();

  /** Rule that converts a {@link Project} on a {@link TableScan}
   * of a {@link org.apache.calcite.schema.ProjectableFilterableTable}
   * to a {@link org.apache.calcite.interpreter.Bindables.BindableTableScan}.
   *
   * @see #PROJECT_INTERPRETER_TABLE_SCAN */
  public static final ProjectTableScanRule PROJECT_TABLE_SCAN =
      ProjectTableScanRule.Config.DEFAULT.toRule();

  /** As {@link #PROJECT_TABLE_SCAN}, but with an intervening
   * {@link org.apache.calcite.adapter.enumerable.EnumerableInterpreter}. */
  public static final ProjectTableScanRule PROJECT_INTERPRETER_TABLE_SCAN =
      ProjectTableScanRule.Config.INTERPRETER.toRule();

  /** Rule that converts a {@link LogicalProject} to a {@link LogicalCalc}.
   *
   * @see #FILTER_TO_CALC */
  public static final ProjectToCalcRule PROJECT_TO_CALC =
      ProjectToCalcRule.Config.DEFAULT.toRule();

  /** Rule that pushes a {@link LogicalProject} past a {@link LogicalWindow}. */
  public static final ProjectWindowTransposeRule PROJECT_WINDOW_TRANSPOSE =
      ProjectWindowTransposeRule.Config.DEFAULT.toRule();

  /** Rule that pushes predicates in a Join into the inputs to the join. */
  public static final FilterJoinRule.JoinConditionPushRule JOIN_CONDITION_PUSH =
      FilterJoinRule.JoinConditionPushRule.JoinConditionPushRuleConfig.DEFAULT.toRule();

  /** Rule that transforms a join with OR conditions into a UNION ALL of multiple joins. */
  public static final JoinExpandOrToUnionRule JOIN_EXPAND_OR_TO_UNION_RULE =
          JoinExpandOrToUnionRule.Config.DEFAULT.toRule();

  /** Rule to add a semi-join into a {@link Join}. */
  public static final JoinAddRedundantSemiJoinRule JOIN_ADD_REDUNDANT_SEMI_JOIN =
      JoinAddRedundantSemiJoinRule.Config.DEFAULT.toRule();

  /** Rule that changes a join based on the associativity rule,
   * ((a JOIN b) JOIN c) &rarr; (a JOIN (b JOIN c)). */
  public static final JoinAssociateRule JOIN_ASSOCIATE =
      JoinAssociateRule.Config.DEFAULT.toRule();

  /** Rule that permutes the inputs to an inner {@link Join}. */
  public static final JoinCommuteRule JOIN_COMMUTE =
      JoinCommuteRule.Config.DEFAULT.toRule();

  /** As {@link #JOIN_COMMUTE} but swaps outer joins as well as inner joins. */
  public static final JoinCommuteRule JOIN_COMMUTE_OUTER =
      JoinCommuteRule.Config.SWAP_OUTER.toRule();

  /** As {@link #JOIN_COMMUTE} but only swaps RIGHT joins to LEFT joins. */
  public static final JoinCommuteRule JOIN_COMMUTE_RIGHT_TO_LEFT =
      JoinCommuteRule.Config.RIGHT_TO_LEFT_ONLY.toRule();

  /** Rule to convert an
   * {@link LogicalJoin inner join} to a
   * {@link LogicalFilter filter} on top of a
   * {@link LogicalJoin cartesian inner join}. */
  public static final JoinExtractFilterRule JOIN_EXTRACT_FILTER =
      JoinExtractFilterRule.Config.DEFAULT.toRule();

  /** Rule that matches a {@link LogicalJoin} whose inputs are
   * {@link LogicalProject}s, and pulls the project expressions up. */
  public static final JoinProjectTransposeRule JOIN_PROJECT_BOTH_TRANSPOSE =
      JoinProjectTransposeRule.Config.DEFAULT.toRule();

  /** As {@link #JOIN_PROJECT_BOTH_TRANSPOSE} but only the left input is
   * a {@link LogicalProject}. */
  public static final JoinProjectTransposeRule JOIN_PROJECT_LEFT_TRANSPOSE =
      JoinProjectTransposeRule.Config.LEFT.toRule();

  /** As {@link #JOIN_PROJECT_BOTH_TRANSPOSE} but only the right input is
   * a {@link LogicalProject}. */
  public static final JoinProjectTransposeRule JOIN_PROJECT_RIGHT_TRANSPOSE =
      JoinProjectTransposeRule.Config.RIGHT.toRule();

  /** As {@link #JOIN_PROJECT_BOTH_TRANSPOSE} but match outer as well as
   * inner join. */
  public static final JoinProjectTransposeRule
      JOIN_PROJECT_BOTH_TRANSPOSE_INCLUDE_OUTER =
      JoinProjectTransposeRule.Config.OUTER.toRule();

  /** As {@link #JOIN_PROJECT_LEFT_TRANSPOSE} but match outer as well as
   * inner join. */
  public static final JoinProjectTransposeRule
      JOIN_PROJECT_LEFT_TRANSPOSE_INCLUDE_OUTER =
      JoinProjectTransposeRule.Config.LEFT_OUTER.toRule();

  /** As {@link #JOIN_PROJECT_RIGHT_TRANSPOSE} but match outer as well as
   * inner join. */
  public static final JoinProjectTransposeRule
      JOIN_PROJECT_RIGHT_TRANSPOSE_INCLUDE_OUTER =
      JoinProjectTransposeRule.Config.RIGHT_OUTER.toRule();

  /** Rule that matches a {@link Join} and pushes down expressions on either
   * side of "equal" conditions. */
  public static final JoinPushExpressionsRule JOIN_PUSH_EXPRESSIONS =
      JoinPushExpressionsRule.Config.DEFAULT.toRule();

  /** Rule that infers predicates from on a {@link Join} and creates
   * {@link Filter}s if those predicates can be pushed to its inputs. */
  public static final JoinPushTransitivePredicatesRule
      JOIN_PUSH_TRANSITIVE_PREDICATES =
      JoinPushTransitivePredicatesRule.Config.DEFAULT.toRule();

  /** Rule that derives IS NOT NULL predicates from a inner {@link Join} and creates
   * {@link Filter}s with those predicates as new inputs of the {@link Join}. */
  public static final JoinDeriveIsNotNullFilterRule JOIN_DERIVE_IS_NOT_NULL_FILTER_RULE =
      JoinDeriveIsNotNullFilterRule.Config.DEFAULT.toRule();

  /** Rule that reduces constants inside a {@link Join}.
   *
   * @see #FILTER_REDUCE_EXPRESSIONS
   * @see #PROJECT_REDUCE_EXPRESSIONS */
  public static final ReduceExpressionsRule.JoinReduceExpressionsRule
      JOIN_REDUCE_EXPRESSIONS =
      ReduceExpressionsRule.JoinReduceExpressionsRule.JoinReduceExpressionsRuleConfig
          .DEFAULT.toRule();

  /** Rule that creates a {@link Join#isSemiJoin semi-join} from a
   * {@link Join}, and it's right keys are unique in its right input.
   */
  public static final SemiJoinRule.JoinOnUniqueToSemiJoinRule JOIN_ON_UNIQUE_TO_SEMI_JOIN =
      SemiJoinRule.JoinOnUniqueToSemiJoinRule.JoinOnUniqueToSemiJoinRuleConfig.DEFAULT.toRule();

  /** Rule that converts a {@link LogicalJoin}
   * into a {@link LogicalCorrelate}. */
  public static final JoinToCorrelateRule JOIN_TO_CORRELATE =
      JoinToCorrelateRule.Config.DEFAULT.toRule();

  /** Rule that flattens a tree of {@link LogicalJoin}s
   * into a single {@link MultiJoin} with N inputs. */
  public static final JoinToMultiJoinRule JOIN_TO_MULTI_JOIN =
      JoinToMultiJoinRule.Config.DEFAULT.toRule();

  /** Rule that creates a {@link Join#isSemiJoin semi-join} from a
   * {@link Join} with an empty {@link Aggregate} as its right input.
   *
   * @see #PROJECT_TO_SEMI_JOIN */
  public static final SemiJoinRule.JoinToSemiJoinRule JOIN_TO_SEMI_JOIN =
      SemiJoinRule.JoinToSemiJoinRule.JoinToSemiJoinRuleConfig.DEFAULT.toRule();

  /** Rule that pushes a {@link Join}
   * past a non-distinct {@link Union} as its left input. */
  public static final JoinUnionTransposeRule JOIN_LEFT_UNION_TRANSPOSE =
      JoinUnionTransposeRule.Config.LEFT.toRule();

  /** Rule that pushes a {@link Join}
   * past a non-distinct {@link Union} as its right input. */
  public static final JoinUnionTransposeRule JOIN_RIGHT_UNION_TRANSPOSE =
      JoinUnionTransposeRule.Config.RIGHT.toRule();

  /** Rule that re-orders a {@link Join} using a heuristic planner.
   *
   * <p>It is triggered by the pattern
   * {@link LogicalProject} ({@link MultiJoin}).
   *
   * @see #JOIN_TO_MULTI_JOIN
   * @see #MULTI_JOIN_OPTIMIZE_BUSHY */
  public static final LoptOptimizeJoinRule MULTI_JOIN_OPTIMIZE =
      LoptOptimizeJoinRule.Config.DEFAULT.toRule();

  /** Rule that finds an approximately optimal ordering for join operators
   * using a heuristic algorithm and can handle bushy joins.
   *
   * <p>It is triggered by the pattern
   * {@link LogicalProject} ({@link MultiJoin}).
   *
   * @see #MULTI_JOIN_OPTIMIZE
   */
  public static final MultiJoinOptimizeBushyRule MULTI_JOIN_OPTIMIZE_BUSHY =
      MultiJoinOptimizeBushyRule.Config.DEFAULT.toRule();

  /** Rule that matches a {@link LogicalJoin} whose inputs are both a
   * {@link MultiJoin} with intervening {@link LogicalProject}s,
   * and pulls the Projects up above the Join. */
  public static final MultiJoinProjectTransposeRule MULTI_JOIN_BOTH_PROJECT =
      MultiJoinProjectTransposeRule.Config.BOTH_PROJECT.toRule();

  /** As {@link #MULTI_JOIN_BOTH_PROJECT} but only the left input has
   * an intervening Project. */
  public static final MultiJoinProjectTransposeRule MULTI_JOIN_LEFT_PROJECT =
      MultiJoinProjectTransposeRule.Config.LEFT_PROJECT.toRule();

  /** As {@link #MULTI_JOIN_BOTH_PROJECT} but only the right input has
   * an intervening Project. */
  public static final MultiJoinProjectTransposeRule MULTI_JOIN_RIGHT_PROJECT =
      MultiJoinProjectTransposeRule.Config.RIGHT_PROJECT.toRule();

  /** Rule that pushes a {@link Join#isSemiJoin semi-join} down in a tree past
   * a {@link Filter}.
   *
   * @see #SEMI_JOIN_PROJECT_TRANSPOSE
   * @see #SEMI_JOIN_JOIN_TRANSPOSE */
  public static final SemiJoinFilterTransposeRule SEMI_JOIN_FILTER_TRANSPOSE =
      SemiJoinFilterTransposeRule.Config.DEFAULT.toRule();

  /** Rule that pushes a {@link Join#isSemiJoin semi-join} down in a tree past
   * a {@link Project}.
   *
   * @see #SEMI_JOIN_FILTER_TRANSPOSE
   * @see #SEMI_JOIN_JOIN_TRANSPOSE */
  public static final SemiJoinProjectTransposeRule SEMI_JOIN_PROJECT_TRANSPOSE =
      SemiJoinProjectTransposeRule.Config.DEFAULT.toRule();

  /** Rule that pushes a {@link Join#isSemiJoin semi-join} down in a tree past a
   * {@link Join}.
   *
   * @see #SEMI_JOIN_FILTER_TRANSPOSE
   * @see #SEMI_JOIN_PROJECT_TRANSPOSE */
  public static final SemiJoinJoinTransposeRule SEMI_JOIN_JOIN_TRANSPOSE =
      SemiJoinJoinTransposeRule.Config.DEFAULT.toRule();

  /** Rule that removes a {@link Join#isSemiJoin semi-join} from a join tree. */
  public static final SemiJoinRemoveRule SEMI_JOIN_REMOVE =
      SemiJoinRemoveRule.Config.DEFAULT.toRule();

  /** Rule that pushes a {@link Sort} past a {@link Union}.
   *
   * <p>This rule instance is for a Union implementation that does not preserve
   * the ordering of its inputs. Thus, it makes no sense to match this rule
   * if the Sort does not have a limit, i.e., {@link Sort#fetch} is null.
   *
   * @see #SORT_UNION_TRANSPOSE_MATCH_NULL_FETCH */
  public static final SortUnionTransposeRule SORT_UNION_TRANSPOSE =
      SortUnionTransposeRule.Config.DEFAULT.toRule();

  /** As {@link #SORT_UNION_TRANSPOSE}, but for a Union implementation that
   * preserves the ordering of its inputs. It is still worth applying this rule
   * even if the Sort does not have a limit, for the merge of already sorted
   * inputs that the Union can do is usually cheap. */
  public static final SortUnionTransposeRule SORT_UNION_TRANSPOSE_MATCH_NULL_FETCH =
      SortUnionTransposeRule.Config.MATCH_NULL_FETCH.toRule();

  /** Rule that copies a {@link Sort} past a {@link Join} without its limit and
   * offset. The original {@link Sort} is preserved but can potentially be
   * removed by {@link #SORT_REMOVE} if redundant. */
  public static final SortJoinCopyRule SORT_JOIN_COPY =
      SortJoinCopyRule.Config.DEFAULT.toRule();

  /** Rule that removes a {@link Sort} if its input is already sorted. */
  public static final SortRemoveRule SORT_REMOVE =
      SortRemoveRule.Config.DEFAULT.toRule();

  /** Rule that merge a {@link Sort} representing the Limit semantics and
   * another {@link Sort} representing the Limit or TOPN semantics. */
  public static final SortMergeRule LIMIT_MERGE =
      SortMergeRule.Config.LIMIT_MERGE.toRule();

  /** Rule that removes keys from a {@link Sort}
   * if those keys are known to be constant, or removes the entire Sort if all
   * keys are constant. */
  public static final SortRemoveConstantKeysRule SORT_REMOVE_CONSTANT_KEYS =
      SortRemoveConstantKeysRule.Config.DEFAULT.toRule();

  /** Rule that removes redundant {@code Order By} or {@code Limit} when its input RelNode's
   * max row count is less than or equal to specified row count.All of them
   * are represented by {@link Sort}*/
  public static final SortRemoveRedundantRule SORT_REMOVE_REDUNDANT =
      SortRemoveRedundantRule.Config.DEFAULT.toRule();

  /** Rule that pushes a {@link Sort} past a {@link Join}. */
  public static final SortJoinTransposeRule SORT_JOIN_TRANSPOSE =
      SortJoinTransposeRule.Config.DEFAULT.toRule();

  /** Rule that pushes a {@link Sort} past a {@link Project}. */
  public static final SortProjectTransposeRule SORT_PROJECT_TRANSPOSE =
      SortProjectTransposeRule.Config.DEFAULT.toRule();

  /** Rule that flattens a {@link Union} on a {@code Union}
   * into a single {@code Union}. */
  public static final UnionMergeRule UNION_MERGE =
      UnionMergeRule.Config.DEFAULT.toRule();

  /** Rule that removes a {@link Union} if it has only one input.
   *
   * @see PruneEmptyRules#UNION_INSTANCE */
  public static final UnionEliminatorRule UNION_REMOVE =
      UnionEliminatorRule.Config.DEFAULT.toRule();

  /** Rule that pulls up constants through a Union operator. */
  public static final UnionPullUpConstantsRule UNION_PULL_UP_CONSTANTS =
       UnionPullUpConstantsRule.Config.DEFAULT.toRule();

  /** Rule that translates a distinct {@link Union}
   * (<code>all</code> = <code>false</code>)
   * into an {@link Aggregate} on top of a non-distinct {@link Union}
   * (<code>all</code> = <code>true</code>). */
  public static final UnionToDistinctRule UNION_TO_DISTINCT =
      UnionToDistinctRule.Config.DEFAULT.toRule();

  /** Rule that translates a {@link Union} to {@link Values}
   * if it's all input are {@link Values}. */
  public static final UnionToValuesRule UNION_TO_VALUES =
      UnionToValuesRule.Config.DEFAULT.toRule();

  /** Rule that rewrite {@link Sample} which is bernoulli to the {@link Filter}. */
  public static final SampleToFilterRule SAMPLE_TO_FILTER =
      SampleToFilterRule.Config.DEFAULT.toRule();

  /** Rule that applies an {@link Aggregate} to a {@link Values} (currently just
   * an empty {@code Values}). */
  public static final AggregateValuesRule AGGREGATE_VALUES =
      AggregateValuesRule.Config.DEFAULT.toRule();

  /** Rule that merges a {@link Filter} onto an underlying
   * {@link org.apache.calcite.rel.logical.LogicalValues},
   * resulting in a {@code Values} with potentially fewer rows. */
  public static final ValuesReduceRule FILTER_VALUES_MERGE =
      ValuesReduceRule.Config.FILTER.toRule();

  /** Rule that merges a {@link Project} onto an underlying
   * {@link org.apache.calcite.rel.logical.LogicalValues},
   * resulting in a {@code Values} with different columns. */
  public static final ValuesReduceRule PROJECT_VALUES_MERGE =
      ValuesReduceRule.Config.PROJECT.toRule();

  /** Rule that merges a {@link Project}
   * on top of a {@link Filter} onto an underlying
   * {@link org.apache.calcite.rel.logical.LogicalValues},
   * resulting in a {@code Values} with different columns
   * and potentially fewer rows. */
  public static final ValuesReduceRule PROJECT_FILTER_VALUES_MERGE =
      ValuesReduceRule.Config.PROJECT_FILTER.toRule();

  /** Rule that reduces constants inside a {@link LogicalWindow}.
   *
   * @see #FILTER_REDUCE_EXPRESSIONS */
  public static final ReduceExpressionsRule.WindowReduceExpressionsRule
      WINDOW_REDUCE_EXPRESSIONS =
      ReduceExpressionsRule.WindowReduceExpressionsRule.WindowReduceExpressionsRuleConfig
          .DEFAULT.toRule();

  /** Rule that flattens a tree of {@link LogicalJoin}s
   * into a single {@link HyperGraph} with N inputs. */
  @Experimental
  public static final JoinToHyperGraphRule JOIN_TO_HYPER_GRAPH =
      JoinToHyperGraphRule.Config.DEFAULT.toRule();

  /** Rule that re-orders a {@link Join} tree using dphyp algorithm.
   *
   * @see #JOIN_TO_HYPER_GRAPH */
  @Experimental
  public static final DphypJoinReorderRule HYPER_GRAPH_OPTIMIZE =
      DphypJoinReorderRule.Config.DEFAULT.toRule();

  /** Rule that expands disjunction in the condition of a {@link Filter}.
   *
   * @see #EXPAND_JOIN_DISJUNCTION_GLOBAL */
  public static final ExpandDisjunctionForTableRule EXPAND_FILTER_DISJUNCTION_GLOBAL =
      ExpandDisjunctionForTableRule.Config.FILTER.toRule();

  /** Rule that expands disjunction in the condition of a {@link Join}.
   *
   * @see #EXPAND_FILTER_DISJUNCTION_GLOBAL */
  public static final ExpandDisjunctionForTableRule EXPAND_JOIN_DISJUNCTION_GLOBAL =
      ExpandDisjunctionForTableRule.Config.JOIN.toRule();

  /** Rule that expands disjunction in the condition of a {@link Filter} for join inputs.
   *
   * @see #EXPAND_JOIN_DISJUNCTION_LOCAL */
  public static final ExpandDisjunctionForJoinInputsRule EXPAND_FILTER_DISJUNCTION_LOCAL =
      ExpandDisjunctionForJoinInputsRule.Config.FILTER.toRule();

  /** Rule that expands disjunction in the condition of a {@link Join} for join inputs.
   *
   * @see #EXPAND_FILTER_DISJUNCTION_LOCAL */
  public static final ExpandDisjunctionForJoinInputsRule EXPAND_JOIN_DISJUNCTION_LOCAL =
      ExpandDisjunctionForJoinInputsRule.Config.JOIN.toRule();

  /** Rule that convert FULL JOIN to LEFT JOIN and RIGHT JOIN. */
  public static final FullToLeftAndRightJoinRule FULL_TO_LEFT_AND_RIGHT_JOIN =
      FullToLeftAndRightJoinRule.Config.DEFAULT.toRule();

  /** Rule that converts true filtered aggregates into CASE-style filtered aggregates. */
  public static final AggregateFilterToCaseRule AGGREGATE_FILTER_TO_CASE =
      AggregateFilterToCaseRule.Config.DEFAULT.toRule();

  /** Rule that remove duplicate {@link Sort} keys. */
  public static final SortRemoveDuplicateKeysRule SORT_REMOVE_DUPLICATE_KEYS =
      SortRemoveDuplicateKeysRule.Config.DEFAULT.toRule();

  /** Rule that converts GROUPING SETS of {@link Aggregate}
   *  into equivalent {@link Union} ALL of GROUP BY operations. */
  public static final AggregateGroupingSetsToUnionRule AGGREGATE_GROUPING_SETS_TO_UNION =
      AggregateGroupingSetsToUnionRule.Config.DEFAULT.toRule();
}