注意:本文基于 Calcite 1.35.0 版本源码进行学习研究,其他版本可能会存在实现逻辑差异,对源码感兴趣的读者请注意版本选择。
前言
在上一篇 Apache Calcite System Catalog 实现探究中,我们介绍了经典的数据库的处理流程,包括:SQL 解析
、SQL 绑定
、SQL 优化
以及计划执行
。SQL 绑定主要的作用是将 SQL 解析生成的 AST 和数据库的元数据进行绑定,从而生成具有语义的 AST。SQL 绑定会通过自底向上的方式遍历 AST,对抽象语法树中的节点进行绑定分析,绑定的过程中会将表、列等元数据附在语法树上,最后生成具有语义的语法树 Bounded AST
。
Calcite 通过 SQL 校验器实现 SQL 绑定,SQL 校验器所需的 System Catalog 信息,我们在上篇文章已经做了详细的介绍,感兴趣的读者可以阅读回顾相关内容。本文将重点介绍 Calcite SQL 校验器的整体设计,梳理校验器中不同类的用途,然后通过一些案例来展示 SQL 校验器的整体流程,并对流程中的关键方法进行代码级别的分析,力求让大家能够深刻理解 Calcite 的 SQL 校验器。
SQL 校验器整体设计
SQL 校验器的核心类为 SqlValidator
,它负责使用 Calcite 元数据信息对 AST 进行验证,最终生成具有语义信息的 AST。在 Calcite 中,可以通过 SqlValidatorUtil.newValidator
方法快速创建一个 SqlValidator。
除了 SqlValidator 校验器类之外,Calcite 为了将 SQL 中的名称解析为对象,还在校验器内部构建了两个对象:SqlValidatorScope
和 SqlValidatorNamespace
,SqlValidatorScope 表示名称解析的范围,代表了在查询中的某一个位置,当前可见的字段名和表名。SqlValidatorNamespace
则表示了校验过程中查询语句的数据源,不同的查询位置都有不同类型的 namespace 类,例如:表名对应的 IdentifierNamespace
,Select 语句对应的 SelectNamespace
,以及 UNION
、EXCEPT
、INTERSECT
对应的 SetopNamespace
。下面我们针对核心的 SqlValidator、SqlValidatorScope 和 SqlValidatorNamespace 分别进行探究,了解其设计细节以及适用场景。
SqlValidator
SqlValidator
校验器根据元数据对 SQL 解析的 AST 进行校验,得到具有语义信息的绑定 AST。SqlValidator 通过访问者模式对 AST 进行校验,调用 SqlNode#validate
方法时,校验器内部会调用 validateXxx 方法,例如:调用 SqlLiteral.validate(SqlValidator, SqlValidatorScope)
会调用 validateLiteral(SqlLiteral);
,调用 SqlCall.validate(SqlValidator, SqlValidatorScope)
则会调用 validCall(SqlCall, SqlValidatorScope);
。
SqlValidator 接口定义了 Calcite 校验器的主要方法,它提供了基础的 getCatalogReader
和 getOperatorTable
方法,分别用于获取元数据信息和运算符、函数。校验 SqlNode 则是通过 validate
方法,会按照 AST 结构进行遍历校验,最终返回已校验 SqlNode。
1 | public interface SqlValidator { |
此外,为了对 SqlValidator 校验过程中的一些行为进行控制,Calcite 提供了 SqlValidator#Config 配置类,通过 with
方法可以方便地设置校验器的属性,常见的属性设置方法如下。
1 | interface Config { |
SqlValidatorScope
TODO
SqlValidatorNamespace
TODO
SQL 校验器执行流程
TODO
结语
TODO
写在最后
笔者因为工作原因接触到 Calcite,前期学习过程中,深感 Calcite 学习资料之匮乏,因此创建了 Calcite 从入门到精通知识星球,希望能够将学习过程中的资料和经验沉淀下来,为更多想要学习 Calcite 的朋友提供一些帮助。