DuckDB V2 基于 PEG 的 SQL 解析器
Daniël ten Wolde 2026-08-20 | 16 分钟 TL;DR:DuckDB v2.0 用基于 PEG 的解析器替换了其源自 PostgreSQL 的 SQL 解析器,该解析器更易于演变并且可以在运行时扩展。我们在 DuckDB 的目标之一是尽可能简化数据库系统的使用。用户通过广泛理解的结构化查询语言(SQL)与系统进行交互。之前的博文已经涵盖了 DuckDB 的友好 SQL,包括 GROUP BY ALL 和使用 SELECT * EXCLUDE (...) 的列选择。然而,在 DuckDB 执行使用这些功能的查询之前,首先必须确定其语法是否有效。这是解析器的工作,而在 DuckDB v2.0 中,我们将其完全替换而不让你察觉。解析器的角色是什么?从高层次来看,DuckDB 通过以下阶段处理 SQL 查询:在这篇博文中,我们聚焦于词法分析器、解析器和转换器:词法分析器:这是第一步,负责将原始输入字符串拆分为标记。这些标记可以分为不同的类别,例如:KEYWORD、NUMBER 或 IDENTIFIER。它也是识别和跳过注释(SQL 中用 -- 或 /* */ 表示) 的地方。解析器:解析器确定这些标记是否遵循 DuckDB 的语法,并产生一个解析结果树。转换器:将通用解析结果转换为 DuckDB 的内部抽象语法树(AST),形成 SQLStatement、TableRef 和 ParsedExpression 等结构。结果 AST 被传递给绑定器。解析器确定查询在语法上是否有效,而绑定器确定其引用的表、列和函数是否实际存在。考虑以下查询:SELECT * WHERE true FROM range (1); 解析器错误:语法错误,接近 "FROM" 第 3 行:FROM range(1); ^^^^ 查询中的每一个独立标记都是有效的,但子句的顺序有 DuckDB 的语法所不接受。友好的 SQL 允许 SELECT 优先和 FROM 优先的语法,但不允许子句以任意顺序出现。相比之下,以下查询在语法上是有效的,因此它通过了解解析器和转换器。然而,由于表 missing_table 不存在,它在绑定器阶段失败。FROM missing_table; 目录错误:名称为 missing_table 的表不存在!第 1 行:FROM missing_table; ^^^^^^^^^^^^^ DuckDB SQL 方言 尽管存在 SQL 标准,但每个数据库系统支持标准的不同部分,并增加其自身的语法和行为。结果的变体通常被称为 SQL 方言。示例包括 PostgreSQL、Oracle、GoogleSQL for BigQuery、MySQL、MariaDB、SQLite、Spark SQL 的方言,以及,当然,DuckDB。DuckDB 的 SQL 紧密遵循 PostgreSQL 的约定,但多年来有所演变。我们添加了自己的功能,如 GROUP BY ALL,以及受其他数据库系统启发的功能。同时,DuckDB 并没有实现 PostgreSQL 行为的每一个方面。因此,DuckDB 讲述了自己的 SQL 方言,我们在这篇文章中称之为 DuckSQL,尽管它仍然深受 PostgreSQL 的影响。这个区别在谈论解析器时很重要。DuckDB 接受的 SQL 方言和用于解析 SQL 的实现是两个不同的事情。对于 DuckDB v2.0,我们正在替换解析器实现并重写其语法。我们没有替换的是 DuckSQL 本身。超越 PostgreSQL 派生的解析器 当 DuckDB 开始时,使用源自 PostgreSQL 的解析器和语法是非常合理的。这个解析器是在 2018 年 DuckDB 的首次提交中就已经存在。它使 DuckDB 拥有了成熟的、经过实战检验的 SQL 语法,许多用户已经熟悉了该语法。我们根据自己的需求调整了解析器,并添加了一个转换器,将生成的 PostgreSQL 风格的解析树转换为 DuckDB 的内部 AST。然而,随着时间的推移,这个解析器也带来了一些缺点。扩展 DuckSQL 意味着修改底层的 YACC/Bison 语法。因为 Bison 生成 LALR(1) 解析器,所以对于语法的看似微小的添加可能会与现有规则相互作用并引入移位/归约或归约/归约冲突。随着 DuckSQL 的增长,修改语法变得越来越困难。 这是我们之前在运行时可扩展的 SQL 解析器的博文背后的动力之一。在那篇博文及其随附的 CIDR 论文中,我们探讨了解析表达式语法(PEG)是否可以为一个可扩展的数据库解析器提供更好的基础。那时,PEG 解析器仍然是一个实验性原型,只能解析 SQL 的一个子集。关于 PEG 解析器的基础知识 在研究我们如何将原型转变为生产解析器之前,让我们简单回顾一下 PEG 是如何描述语言的。PEG 由命名规则组成,用于描述输入应如何匹配。考虑下面 DuckDB 新语法中的一些规则。
本站免费、广告极少。如果觉得有帮助,可以请我们喝杯咖啡 —— 任何金额都对持续运营有实际帮助。
☕请我喝杯咖啡