[ 
https://issues.apache.org/jira/browse/CALCITE-3923?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17134592#comment-17134592
 ] 

Julian Hyde commented on CALCITE-3923:
--------------------------------------

There's now a PR for review: [https://github.com/apache/calcite/pull/2024]

Here's the TL;DR:

Previously, it was not easy to customize, re-use or extend planner rules. If 
you wished to customize a rule (i.e. create a new instance of a rule with 
different properties) you would have to call the rule's constructor. Frequently 
the required constructor did not exist, so we would have to add a new 
constructor and deprecate the old one.

After this change, you start off from an instance of the rule, modify its 
configuration, and call toRule() on the configuration. (Rule constructors are 
now private, because only the configuration ever calls them.)

A good illustration of this is {{DruidRules}}, which used to contain many 
sub-classes. Those sub-classes are no longer needed. Old code:
{code:java}
  public static final DruidSortProjectTransposeRule SORT_PROJECT_TRANSPOSE =
      new DruidSortProjectTransposeRule(RelFactories.LOGICAL_BUILDER);

    public static class DruidSortProjectTransposeRule
        extends SortProjectTransposeRule {
      public DruidSortProjectTransposeRule(RelBuilderFactory relBuilderFactory) 
{
        super(
            operand(Sort.class,
                operand(Project.class, operand(DruidQuery.class, none()))),
            relBuilderFactory, null);
      }
    }
{code}
New code:
{code:java}
  public static final SortProjectTransposeRule SORT_PROJECT_TRANSPOSE =
      SortProjectTransposeRule.INSTANCE.config
          .withOperandFor(Sort.class, Project.class, DruidQuery.class)
          .toRule();
{code}
The change maintains backwards compatibility to a large degree. In a few 
places, I had to change rule instances from type {{RelOptRule}} to 
{{Supplier<RelOptRule>}}, to avoid deadlocks during class loading. For 
instance, instead of writing {{FilterJoinRule.FILTER_ON_JOIN}} you must now 
write {{FilterJoinRule.FILTER_ON_JOIN.get()}}.

> Refactor how planner rules are parameterized
> --------------------------------------------
>
>                 Key: CALCITE-3923
>                 URL: https://issues.apache.org/jira/browse/CALCITE-3923
>             Project: Calcite
>          Issue Type: Bug
>            Reporter: Julian Hyde
>            Assignee: Julian Hyde
>            Priority: Major
>             Fix For: 1.24.0
>
>          Time Spent: 10m
>  Remaining Estimate: 0h
>
> People often want different variants of planner rules. An example is 
> {{FilterJoinRule}}, which has a 'boolean smart’ parameter, a predicate (which 
> returns whether to pull up filter conditions), operands (which determine the 
> precise sub-classes of {{RelNode}} that the rule should match) and a 
> {{RelBuilderFactory}} (which controls the type of {{RelNode}} created by this 
> rule).
> Suppose you have an instance of {{FilterJoinRule}} and you want to change 
> {{smart}} from true to false. The {{smart}} parameter is immutable (good!) 
> but you can’t easily create a clone of the rule because you don’t know the 
> values of the other parameters. Your instance might even be (unbeknownst to 
> you) a sub-class with extra parameters and a private constructor.
> So, my proposal is to put all of the config information of a {{RelOptRule}} 
> into a single {{config}} parameter that contains all relevant properties. 
> Each sub-class of {{RelOptRule}} would have one constructor with just a 
> ‘config’ parameter. Each config knows which sub-class of {{RelOptRule}} to 
> create. Therefore it is easy to copy a config, change one or more properties, 
> and create a new rule instance.
> Adding a property to a rule’s config does not require us to add or deprecate 
> any constructors.
> The operands are part of the config, so if you have a rule that matches a 
> {{EnumerableFilter}} on an {{EnumerableJoin}} and you want to make it match 
> an {{EnumerableFilter}} on an {{EnumerableNestedLoopJoin}}, you can easily 
> create one with one changed operand.
> The config is immutable and self-describing, so we can use it to 
> automatically generate a unique description for each rule instance.
> (See the email thread [[DISCUSS] Refactor how planner rules are 
> parameterized|https://lists.apache.org/thread.html/rfdf6f9b7821988bdd92b0377e3d293443a6376f4773c4c658c891cf9%40%3Cdev.calcite.apache.org%3E].)



--
This message was sent by Atlassian Jira
(v8.3.4#803005)

Reply via email to