Well it's not accurately an infinite loop, let me explain.

First of all, this is the loop (I'm using Drill v1.9, which uses Calcite
v1.4)
https://github.com/apache/calcite/blob/branch-1.4/core/src/main/java/org/apache/calcite/plan/hep/HepPlanner.java#L389

The nMatches variable keeps on increasing without breaking the loop.
Theoretically it should eventually break the loop, but I can't accept this
as a solution because it would take minutes to just plan a query ! There
must be another efficient way to break the loop.

I *assume* since Calcite v1.4 doesn't support unparsing OFFSET and FETCH
clauses, Drill tries to apply this pagination using a *DrillLimitRel* node.
But this implies pulling the whole set of data from the JDBC source, then
filtering it within Drill, which is a huge waste for huge datasets if you
ask me. Please correct me if I'm wrong.

*My query:* SELECT CT_ID FROM gelbana.SLS.CTS LIMIT 3

Which is planned as a
*LogicalSort* -> *LogicalProject* -> *JdbcTableScan*

*LogicalSort* is then converted into a Drill specific node which is
*DrillLimitRel*.

*LogicalSort* is the node that holds the fetch, offset and sorting
information. I'm trying to pushdown the fetch value (only if its a literal
and there is no offset specified) to a custom scan node. Then I can pass
the fetch value to the Jdbc statement
<https://docs.oracle.com/javase/8/docs/api/java/sql/Statement.html#setMaxRows-int->
and
achieve the limit I need.

I'm trying to do so by wrapping the *JdbcTableScan* and another custom Jdbc
scan node (i.e. *GelbanaJdbcJoin*), within a new kind of JdbcRel
implementation. This implementation exposes the same methods a *JdbcRel*
would, and the implementation of most of these methods just calls the
equivalent method of the wrapped JdbcRel node. The code the below.

What happens is that the previously mentioned loop keeps on going on and on
without breaking. I appreciate if someone tells me where did I mess up ?

*My rule*
public class GelbanaLimitRule extends RelOptRule {

    public GelbanaLimitRule() {
        super(operand(LogicalSort.class, operand(LogicalProject.class,
operand(JdbcRel.class, any()))), "GelbanaPushdownLimit");
    }

    @Override
    public boolean matches(RelOptRuleCall call) {
        LogicalSort limit = (LogicalSort) call.rels[0];
        RelNode input = call.rels[2];

        boolean jdbcInputCheck = input.getClass() == JdbcTableScan.class ||
input.getClass() == GelbanaJdbcJoin.class;
        return jdbcInputCheck && limit.fetch != null &&
limit.fetch.getClass() == RexLiteral.class && limit.offset == null;
    }

    @Override
    public void onMatch(RelOptRuleCall call) {
        LogicalSort limit = (LogicalSort) call.rels[0];
        LogicalProject project = (LogicalProject) call.rels[1];
        JdbcRel input = (JdbcRel) call.rels[2];

        BigDecimal limitValue = (BigDecimal) ((RexLiteral)
limit.fetch).getValue();

        GelbanaScanWithLimit newInput = new GelbanaScanWithLimit(input,
limitValue.intValue());
        LogicalProject newProject = project.copy(project.getTraitSet(),
newInput, project.getProjects(), project.getRowType());
        Sort newLimit = limit.copy(limit.getTraitSet(), newProject,
limit.getCollation());

        call.transformTo(newLimit);
    }
}

This is a portion of the code of the *GelbanaScanWithLimit* node.

public class GelbanaScanWithLimit implements JdbcRel {
    private JdbcRel input;
    private Integer limit;

    public GelbanaScanWithLimit(JdbcRel input, Integer limit) {
        this.input = input;
        this.limit = limit;
    }

    public boolean hasLimit() {
        return this.limit != null;
    }

    public int getLimit() {
        assert hasLimit();
        return this.limit;
    }

    public RelOptCost computeSelfCost(RelOptPlanner planner) {
        return planner.getCostFactory().makeZeroCost(); //It's the best
case for me to push down *JdbcTableScan*s and joins to my datasource, with
limits of course
    }

    // More methods exist to expose the wrapped *JdbcRel* node. The upper
methods override the equivalent ones of the wrapped *JdbcRel* node.
}

Thanks !

*---------------------*
*Muhammad Gelbana*

Reply via email to