Calcite实现方言转换
1、定义
Calcite能够 通过解析Sql为SqlNode,再将SqlNode转化为特定数据库的方言的形式实现Sql的统一 。
我们知道,Calcite一般会有四个阶段:parse、validate、optimize和execute。其中,在parse和validate阶段,会生成一个parse tree,树中的节点都是SqlNode的类型。在optimize节点,Calcite会将parse tree转换为RelNode,同时进行一些优化,这属于logical plan。最终在execute阶段,将logical plan转换为物理执行计划来执行。
其中,Calcite目前提供了一些方言转换的功能,可以将SqlNode和RelNode转成指定计算引擎的SQL方言,例如Mysql、Presto等,相关的方言转换类如下所示(SqlDialect为基类):
2、SQLNode介绍
先简单看一下SqlNode是什么。在使用Calcite的parser进行解析之后,SQL就会被转换成一颗parse tree,树中每一个节点都对应一个SqlNode。对于非叶子结点,基本都是一个SqlCall,继承SqlNode。而我们常见的各种SQL类型,都是继承了SqlCall,例如select查询,对应的是SqlSelect;create、drop等ddl,对应的是SqlDdl等。这里我们看下一个SqlSelect的组成:
可以看到一个SqlSelect的parse tree主要包含了selectList、from、where等部分,每个部分又由其各自的成员组成。我们在进行方言转换的时候,就是要对这些SqlNode进行处理(从RelNode -> SqlNode -> 方言Sql 的过程中进行方言转换)。
3、方言转换使用
3.1、Demo
下面以‘PrestoSqlDialect’为例子:
SqlParser parser = SqlParser.create(sql, SqlParser.Config.DEFAULT);
SqlNode sqlNode = parser.parseStmt();
sqlNode.toSqlString(PrestoSqlDialect.DEFAULT)
主要分为三个步骤:
1、根据sql和SqlParser.Config构造一个SqlParser,这里的Config可以配置一些引用标识符、大小写保留等参数;
2、调用parseStmt方法,就可以得到一个parse tree,这里的sqlNode是树的root节点,一般就是SqlSelect。
3、调用toSqlString方法,就可以传入指定的SqlDialect类,实现特定的方言转换。这里我们就传入了PrestoSqlDialect,将SQL转成presto的SQL输出。
2、SqlNode.toSqlString源码解析
https://www.atbigapp.com/component/calcite/blog/1815594964532256768