Calcite 手动执行 RelNode
10 Nov 20222022.12.06 更新:控制节点的执行顺序也可以使用 EnumerableRel 只是稍微麻烦点,但也挺优雅。
项目里有个需求,需要让 Calcite 里 TableScan 按顺序执行,后执行的 TableScan 依赖前面 TableSacn 执行的返回数据。试了各种方法,要么是因为 Calcite 运行机制导致无法生效,要么就是太不优雅自己无法接受。后来想了个法子就是不依赖 Calcite 框架来运行 TableScan,自己手动运行来控制前后顺序并传递变量。
办法也很简单就是直接用 Interpreter 来执行,不过前提是要运行的节点是 BindableRel(Interpreter 运行节点使用了Nodes.CoreCompiler
不仅支持 BindableRel 还支持框架本身提供的节点)。最终,为了实现自己运行节点,需要我们写一个简单的优化规则,建议是直接对 Logical 的节点优化,这样处理比较方便。然后就是构造一个 BindableRel 把待手动运行的节点作为属性保存起来,最后在 run 方法里调用 Interpreter 运行节点即可。示例代码:
/**
* @param DataContext 上下文
* @param RelNode 待手动运行的节点
*/
private List<Object[]> interpret(DataContext dataContext, RelNode root) {
try(
Interpreter interpreter = new Interpreter(dataContext, root);
) {
List<Object[]> result = new ArrayList<>();
Enumerator<Object[]> enumerator = interpreter.enumerator();
while (enumerator.moveNext()) {
result.add(enumerator.current());
}
return result;
}
}