解析阶段 包含两个部分
在 gram.y
和 scan.l
中定义的 解析器 是使用 Unix 工具 bison 和 flex 构建的。
转换过程 对解析器返回的数据结构进行修改和增强。
解析器必须检查查询字符串(作为纯文本到达)的语法是否有效。如果语法正确,则会构建一个 解析树 并将其返回;否则,将返回错误。解析器和词法分析器使用著名的 Unix 工具 bison 和 flex 实现。
词法分析器 在 scan.l
文件中定义,负责识别 标识符、SQL 关键字 等。对于找到的每个关键字或标识符,都会生成一个 标记 并将其传递给解析器。
解析器在 gram.y
文件中定义,由一组 语法规则 和 动作 组成,这些动作在规则触发时执行。动作的代码(实际上是 C 代码)用于构建解析树。
使用程序 flex 将 scan.l
转换为 C 源文件 scan.c
,并使用 bison 将 gram.y
转换为 gram.c
。完成这些转换后,可以使用普通的 C 编译器创建解析器。切勿对生成的 C 文件进行任何更改,因为下次调用 flex 或 bison 时,它们将被覆盖。
提到的转换和编译通常使用 PostgreSQL 源代码分发版附带的 makefile 自动完成。
对 bison 或 gram.y
中给出的语法规则的详细描述超出了本手册的范围。有很多书籍和文档涉及 flex 和 bison。在开始研究 gram.y
中给出的语法之前,您应该熟悉 bison,否则您将无法理解那里发生了什么。
解析阶段仅使用有关 SQL 语法结构的固定规则创建解析树。它不会在系统目录中进行任何查找,因此无法理解请求的操作的详细语义。解析器完成后, 转换过程 将解析器返回的树作为输入,并执行理解查询引用了哪些表、函数和运算符所需的语义解释。用于表示此信息的数据结构称为 查询树。
将原始解析与语义分析分开的原因为,系统目录查找只能在事务中执行,并且我们不希望在收到查询字符串后立即启动事务。原始解析阶段足以识别事务控制命令(BEGIN
、ROLLBACK
等),并且可以在没有任何进一步分析的情况下正确执行这些命令。一旦我们知道我们正在处理一个实际的查询(例如 SELECT
或 UPDATE
),如果我们尚未处于事务中,则可以启动事务。只有这样才能调用转换过程。
转换过程创建的查询树在大多数地方在结构上类似于原始解析树,但在细节上存在许多差异。例如,解析树中的 FuncCall
节点表示语法上类似于函数调用的内容。这可能会转换为 FuncExpr
或 Aggref
节点,具体取决于引用的名称最终是普通函数还是聚合函数。此外,有关列和表达式结果的实际数据类型的的信息也会添加到查询树中。
如果您在文档中看到任何不正确的内容,与您对特定功能的体验不符,或者需要进一步澄清,请使用 此表单 报告文档问题。