解析器阶段由两部分组成:
解析器定义在 gram.y 和 scan.l 中,它使用 Unix 工具 bison 和 flex 构建。
转换过程,它会对解析器返回的数据结构做修改和补充。
解析器必须检查查询字符串(它以纯文本形式到达)是否具有有效语法。如果语法正确,就会构造出一棵 语法解析树 并返回;否则会返回错误。解析器和词法分析器是使用著名的 Unix 工具 bison 和 flex 实现的。
词法分析器定义在文件 scan.l 中,负责识别 标识符、SQL 关键字 等。每找到一个关键字或标识符,就会生成一个 词元 并交给解析器。
解析器定义在文件 gram.y 中,由一组 语法规则 和 动作 组成,每当某条规则被触发时,对应动作就会执行。动作中的代码(实际上是 C 代码)用于构造语法解析树。
文件 scan.l 会被转换成 C 源文件 scan.c,所用程序是 flex;而 gram.y 则会被转换成 gram.c,所用程序是 bison。这些转换完成之后,就可以使用普通的 C 编译器来构建解析器。绝不要修改这些生成出来的 C 文件,因为下一次调用 flex 或 bison 时,它们都会被覆盖。
上述转换和编译通常都是借助 makefiles 自动完成的,这些文件随 PostgreSQL 源代码发行版一同提供。
对 bison 的详细描述,或者对 gram.y 中给出的语法规则的说明,都超出了本手册的范围。有许多书籍和文档专门讨论 flex 和 bison。在开始研究之前,你应该先熟悉 bison,然后再去看 gram.y 中给出的语法,否则你将无法理解其中发生了什么。
解析器阶段仅依据 SQL 语法结构的固定规则创建一棵语法解析树。它不会在系统目录中做任何查找,因此不可能理解所请求操作的详细语义。解析器完成之后,转换过程会接收解析器返回的树,并进行必要的语义解释,以理解查询引用了哪些表、函数和操作符。为表示这些信息而构建的数据结构称为 查询树。
之所以将原始解析与语义分析分开,是因为系统目录查找只能在事务内部进行,而我们不希望在刚收到查询字符串时就立刻启动事务。原始解析阶段已经足以识别事务控制命令(BEGIN、ROLLBACK 等),因此这些命令可以在无需进一步分析的情况下被正确执行。一旦我们知道当前处理的是实际查询(例如 SELECT 或 UPDATE),如果尚未处于事务中,就可以启动事务。只有在那之后才能调用转换过程。
转换过程创建的查询树在大多数地方的结构都与原始语法解析树相似,但在细节上有许多不同。例如,语法解析树中的一个 FuncCall 节点表示某个在语法上看起来像函数调用的东西。它可能被转换成 FuncExpr 节点,也可能被转换成 Aggref 节点,这取决于被引用的名称最终被判定为普通函数还是聚合函数。此外,关于列和表达式结果的实际数据类型的信息也会被加入到查询树中。
如果您发现文档中有不正确的内容、与您使用特定功能的经验不符或需要进一步说明,请使用此表单来报告文档问题。