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;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM