Vladimir Dolzhenko created CALCITE-595:
------------------------------------------

             Summary: planner doesn't care about cheaper transformation plan 
                 Key: CALCITE-595
                 URL: https://issues.apache.org/jira/browse/CALCITE-595
             Project: Calcite
          Issue Type: Bug
            Reporter: Vladimir Dolzhenko
            Assignee: Julian Hyde


The rule splits the condition - the 1st part to TableScan another keeps to a 
LogicalFilter.

Despite of rule execution - another plan (with split condition) even has not 
been calculated - computeSelfCost executes only in case of null condition.

{code}
@Test public void testAnotherTableFilter() throws Exception {
    final SchemaPlus rootSchema = Frameworks.createRootSchema(true);
    rootSchema.add("ANOTHER", new AnotherTable());

    final FrameworkConfig config = Frameworks.newConfigBuilder()
        .parserConfig(SqlParser.Config.DEFAULT)
        .defaultSchema(rootSchema)
        .traitDefs((List<RelTraitDef>) null)
        .programs(Programs.heuristicJoinOrder(Programs.RULE_SET, true, 2))
        .build();
    Planner planner = Frameworks.getPlanner(config);
    SqlNode parse = planner.parse("select * from ANOTHER where name='a' AND 
type='b'");

    SqlNode validate = planner.validate(parse);
    RelNode convert = planner.convert(validate);
    RelTraitSet traitSet = planner.getEmptyTraitSet()
        .replace(EnumerableConvention.INSTANCE);
    RelNode transform = planner.transform(0, traitSet, convert);
    final String actual = toString(transform);
    assertThat(actual, containsString("EnumerableProject(NAME=[$0], 
TYPE=[$1])\n" +
        "  EnumerableFilter(condition=[=(CAST($0):VARCHAR(1) CHARACTER SET 
\"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\", 'a')])\n" +
        "    AnotherTableScan(table=[[ANOTHER]])"));
  }

  public class AnotherTable extends AbstractTable implements TranslatableTable {

    public RelNode toRel(RelOptTable.ToRelContext context,
                         RelOptTable relOptTable) {
      return new AnotherTableScan( context.getCluster(),
          context.getCluster().traitSetOf( EnumerableConvention.INSTANCE ),
          relOptTable );
    }

    public RelDataType getRowType(RelDataTypeFactory typeFactory) {
      RelDataTypeFactory.FieldInfoBuilder builder = typeFactory.builder();
      builder.add("NAME", typeFactory.createJavaType( String.class) );
      builder.add("TYPE", typeFactory.createJavaType( String.class) );
      return builder.build();
    }
  }

  static class AnotherTableScanRule extends RelOptRule {
    private AnotherTableScanRule() {
      super(
          operand(
              LogicalFilter.class,
              operand(AnotherTableScan.class, any())));
    }

    public void onMatch( RelOptRuleCall call ) {
      final LogicalFilter filter = call.rel( 0 );
      final AnotherTableScan tableScan = call.rel( 1 );

      final RexNode newScanCondition = filter.getCondition();
      final RelTraitSet restTableScanTraitSet = tableScan.getTraitSet();

      final RelNode newTableScan = tableScan.copy( restTableScanTraitSet, 
ImmutableList.<RelNode>of(), newScanCondition );

      RexNode newFilterCondition =
          newScanCondition.getKind() == SqlKind.AND ? RelOptUtil.conjunctions( 
newScanCondition ).get( 0 ) : newScanCondition;

      System.out.println(newScanCondition + " > " + newScanCondition);

      final RelTraitSet filterTraitSet = filter.getTraitSet();
      final RelNode wrappedFilter = filter.copy( filterTraitSet, newTableScan, 
newFilterCondition );

      call.transformTo( wrappedFilter );
    }
  }

  public static class AnotherTableScan extends TableScan implements 
EnumerableRel {

    private final RexNode condition;

    public AnotherTableScan(RelOptCluster cluster, RelTraitSet traits, 
RelOptTable table) {
      this(cluster, traits, table, null);
    }

    public AnotherTableScan(RelOptCluster cluster, RelTraitSet traits, 
RelOptTable table, RexNode condition) {
      super(cluster, traits, table);
      this.condition = condition;
    }

    public Result implement(EnumerableRelImplementor implementor, Prefer pref) {
      return null;
    }

    @Override
    public void register(RelOptPlanner planner) {
      planner.addRule(new AnotherTableScanRule());
    }

    public RelNode copy(RelTraitSet traitSet, List<RelNode> inputs, RexNode 
condition) {
      assert inputs.isEmpty();
      final AnotherTableScan tableScan = new AnotherTableScan(getCluster(), 
traitSet, getTable(), condition);
      return tableScan;
    }

    @Override
    public RelOptCost computeSelfCost(RelOptPlanner planner) {
      final RelOptCost relOptCost = super.computeSelfCost(planner);
      final RelOptCost cost = relOptCost.multiplyBy(1f / 
(RelOptUtil.conjunctions(condition).size() + 1));
      System.out.println(condition + " = " + cost);
      return cost;
    }
  }
{code}



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)

Reply via email to