文章目录
我们知道,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等,相关的方言转换类如下所示:
本我们主要看一下,Calcite针对SqlNode的方言转换是如何实现。
SqlNode介绍
先简单看一下SqlNode是什么。在使用Calcite的parser进行解析之后,SQL就会被转换成一颗parse tree,树中每一个节点都对应一个SqlNode。对于非叶子结点,基本都是一个SqlCall,继承SqlNode。而我们常见的各种SQL类型,都是继承了SqlCall,例如select查询,对应的是SqlSelect;create、drop等ddl,对应的是SqlDdl等。这里我们看下一个SqlSelect的组成:

可以看到一个SqlSelect的parse tree主要包含了select list、from、where等部分,每个部分又由其各自的成员组成。我们在进行方言转换的时候,就是要对这些SqlNode进行处理。
方言转换使用
常见的使用方式如下:
SqlParser parser = SqlParser.create(sql, SqlParser.Config.DEFAULT);
SqlNode sqlNode = parser.parseStmt();
sqlNode.toSqlString(PrestoSqlDialect.DEFAULT)
主要分为三个步骤:
- 根据sql和SqlParser.Config构造一个SqlParser,这里的Config可以配置一些引用标识符、大小写保留等参数;
- 调用parseStmt方法,就可以得到一个parse tree,这里的sqlNode是树的root节点,一般就是SqlSelect。
- 调用toSqlString方法,就可以传入指定的SqlDialect类,实现特定的方言转换。这里我们就传入了PrestoSqlDialect,将SQL转成presto的SQL输出。
方言转换代码解析
下面我们就来看一下,Calcite是如何实现这种方言转换的功能。
SqlNode.toSqlString方法
主要的处理逻辑位于toSqlString方法,相关的代码调用如下所示:
toSqlString(SqlNode.java):187
-toSqlString(SqlNode.java):178
--toSqlString(SqlNode.java):156
---unparse(SqlSelect.java):261
----unparseCall(PrestoSqlDialect.java):123
这里调用了toSqlString的三个重载方法,我们依次来看一下:
//SqlNode.java
public SqlString to

本文深入解析Apache Calcite在SQL解析和优化过程中如何进行方言转换,包括SqlNode的结构与作用,以及如何通过unparse方法将SqlNode转换为特定方言,如Presto的SUBSTRING到SUBSTR、APPROX_COUNT_DISTINCT到APPROX_DISTINCT的转换,并探讨了GROUP BY ROLLUP在MySQL中的方言重写。

260

被折叠的 条评论
为什么被折叠?



