Calcite分析 -- Implement

Calcite Version:1.26.0

CsvTest

 

select "EMPNO", "JOINTIMES" from "DATE" order by "JOINTIMES"

到优化前的调用栈,

 

其中avatica,是calcite项目中一个独立的子项目,用于封装和server之间的交互,参考,http://people.apache.org/~elserj/calcite/docs/avatica_overview.html

 

Optimize

在prepareSql中,先调用的是Optimize,

经过优化生成的Cheapest计划,

Programs,对于优化过程的封装,

 

可以看到Volcano只是program1,前面还有去关联,trimFields的Hep优化,后面还有calcRules的Hep优化,

这个Calc算子是Project和Filter的结合,目的就是为了减少算子?

 

这里会触发到EnumerableProjectToCalcRule,将project算子转换为Calc

 

 

implement

目的是将物理算子转换成Linq4J的expressionTree,Expression是什么意思,参考C#里面的LinQ

从而通过将ExpressionTree,bind到一个context,形成可执行代码,最终获取Enumerable的实现。

 

CalcitePrepareImpl.implement

 

EnumerableInterpretable

 

EnumerableRelImplementor

调用算子自身的implement函数,

 

EnumerableSort

 

递归调用child的implement,

最终调用到,EnumerableTableScan

到这implement调用栈,如前所说,目的就是调用各个算子自身的implement,实现转换

  

 

调用getExpression,

 

 

最终调用到,tableExpression,

生成是实际是,MethodCallExpression,” Represents a call to either a static or an instance method“,

表示这里的Expression表示函数调用,后面显示出具体的调用是什么,toString会accept一个ExpressionWriter

其可以由Expression.call生成,这里是调用BuildInMethod.Schema_Get_Table,参数是一个Expressions.constant

 

Result

Blocks.toBlock,把一堆Expression封装成一个block,

implementor.result,意思要得到这个block执行的Result,

Result这里是一个封装,包含,

PhysType,每个字段的类型和名称

format,row的形式,这里是array,其他的还有list,row等

block,代码段,这里原先的EnumerableTableScan,已经implement成一个Expression tree,这个tree就代表代码段

 

回到EnumerableCalc,implement

第一步生成代码,input.current,

  

生成moveNext,

 

生成Project逻辑,

{
  final Object[] current = (Object[]) inputEnumerator.current();
  final Object input_value = current[0];
  final Object input_value0 = current[3];
  return new Object[] {
      input_value,
      input_value0};
}

  

最后拼出一个完整的逻辑,

递归回到EnumerableSort,这里的逻辑也比较简单,就是调用内置的orderBy函数。

这样就完成了所有算子的implement。

 

EnumerableRelImplementor.implementRoot

继续将上面得到block,封装到bind函数中,并生成baz类

  

返回到EnumerableInterpretable.toBindable

这里就是将implement得到的class,调用getBindable,即用Janino生成class,并创建实例,

 

得到的Bindable是啥,

bind接口,将statement绑定到某个DataContext上,从而能执行得到Enumerable的结果。

 

这里最终生成的Bindable为,

实际使用时,调用bind得到Enumerable,

用这个迭代器的接口,next和current就可以真正的获取数据,从而完成执行

public org.apache.calcite.linq4j.Enumerable bind(final org.apache.calcite.DataContext root) {
  final org.apache.calcite.linq4j.Enumerable _inputEnumerable = org.apache.calcite.schema.Schemas.enumerable((org.apache.calcite.schema.ScannableTable) root.getRootSchema().getSubSchema("BUG").getTable("DATE"), root);
  final org.apache.calcite.linq4j.AbstractEnumerable child = new org.apache.calcite.linq4j.AbstractEnumerable(){
    public org.apache.calcite.linq4j.Enumerator enumerator() {
      return new org.apache.calcite.linq4j.Enumerator(){
          public final org.apache.calcite.linq4j.Enumerator inputEnumerator = _inputEnumerable.enumerator();
          public void reset() {
            inputEnumerator.reset();
          }

          public boolean moveNext() {
            return inputEnumerator.moveNext();
          }

          public void close() {
            inputEnumerator.close();
          }

          public Object current() {
            final Object[] current = (Object[]) inputEnumerator.current();
            final Object input_value = current[0];
            final Object input_value0 = current[3];
            return new Object[] {
                input_value,
                input_value0};
          }

        };
    }

  };
  return child.orderBy(new org.apache.calcite.linq4j.function.Function1() {
      public Long apply(Object[] v) {
        return (Long) v[1];
      }
      public Object apply(Object v) {
        return apply(
          (Object[]) v);
      }
    }
    , org.apache.calcite.linq4j.function.Functions.nullsComparator(false, false));
}


public Class getElementType() {
  return java.lang.Object[].class;
}

 

posted on 2021-10-13 19:36  fxjwind  阅读(647)  评论(0编辑  收藏  举报