上一篇文章我们介绍了 Calcite SQL 解析的原理以及如何扩展 SQL 语法,本篇我们将进入 SQL 执行的下一个阶段:元数据验证。
二、Calcite 元数据验证
SQL 成功解析为抽象语法树后,接下来需要对整条 SQL 的语义和元数据进行验证,判断 SQL 是否满足下一步计算的要求。
判断一句 SQL 是否正确至少包含以下几点:
- 查询的库表列是否存在。
- SQL 的语义是否正确。
- 验证操作符,判断使用的操作符或者函数是否存在,并被正确地使用,例如数据类型、参数个数等是否正确。
我们可以用以下 SQL 为例来探究 Sql 验证的过程。
SELECT col1, avg(col2)
FROM t1,
(SELECT col3 FROM t2) AS s1
WHERE col4 > col5
GROUP BY col1;
在 Calcite 中验证 SQL 是否合法使用 SqlValidator,它的初始化方式如下:
protected SqlValidatorImpl(
SqlOperatorTable opTab,
SqlValidatorCatalogReader catalogReader,
RelDataTypeFactory typeFactory,
Config config)
SqlOperatorTable 提供 SQL 验证所需要的所有操作符,函数、‘>’、‘<’ 等都属于操作符;SqlValidatorCatalogReader 提供验证需要的元数据信息,包括 Catalog、Schema等;RelDataTypeFactory 提供验证过程中字段类型的相互转换、例如函数返回值类型和精度信息等。Config 可以自定义一些配置,例如是否开启类型强制转换、是否开启 SQL 重写等等。
2.1 验证库表列是否存在
库和表的验证比较好理解,由于大多数的 OLAP 引擎有多个数据源和数据空间,并且支持联邦查询,所以 SQL 中库表往往都是全名称形式存在(或者使用 use 语句指定),形如 catalog.schema.table(例如 hive.tpcds.store),这样一来,我们就能确定唯一一张表的位置。此外,在 Calcite 验证器中有两个重要的抽象,作用域(Scope)和命名空间(Namespace)。
- 作用域
Scope 用来表示一个字段或者一个表达式的作用域,简单理解就是验证时知道 select 的字段可能出现在哪张表中,这样便能校验这个字段是否存在。以开头的 SQL 语句为例,表达式的作用域如下:
col1, col2 可能出现在 t1, s1
col3 只能出现在 t2 中
col4, col5 可能出现在 t1, s1
当解析验证一个表达式的时候,如果验证通过,就会将表达式包装成一个 Namespace 返回。在验证 SELECT * FROM hive.tpcds.store 表达式时,会解析和重组 hive.tpcds.store 的每级 schema,通过 CatalogReader 的 getTable() 方法获取元数据信息,判断表和字段是否存在。第一步,Calcite 会验证 RootSchema,也就是 Catalog 是否存在,然后依次向上拼接 schema,验证 hive.tpcds 是否存在,最后验证 hive.tpcds.store。如果全

本文深入探讨了Calcite SQL解析后的元数据验证过程,包括库表列存在性验证、SQL语义验证和操作符验证。通过实例展示了如何在Calcite中扩展SQL语法和验证函数,同时指出了在生产环境中可能遇到的挑战。
最低0.47元/天 解锁文章
412

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



