Calcite SQL 解析、语法扩展、元数据验证原理与实战(下)

上一篇文章我们介绍了 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,也就是 Ca

你可能感兴趣的:(技术实战,sql,数据库)