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