46.3. 分析器阶段

分析器阶段含两个部分:

46.3.1. 分析器

分析器必须检查(以纯 ASCII 文本方式到来的)查询字符串的语法。如果语法正确, 则创建一个分析树并将之传回,否则,返回一个错误。 实现分析器和词法器使用了著名的 Unix 工具bisonflex

词法器在文件scan.l里定义, 负责识别标识符SQL 关键字等。 对于发现的每个关键字或者标识符都会生成一个记号并且传递给分析器。

分析器在文件gram.y里定义并且包含一套语法规则 以及触发规则时执行的动作。动作代码(实际上是 C 代码)用于建立分析树。

文件scan.lflex转换成 C 源文件 scan.c,而gram.ybison 转换成gram.c。在完成这些转换后,一个通用的 C 编译器就可以用于创建分析器。 千万不要对生成的 C 源文件做修改,因为下一次调用flexbison时会把它们覆盖。

注意: 上面提到的转换和编译是使用跟随PostgreSQL发布的 makefiles自动完成的。

bison或者gram.y 里的语法规则的详细描述超出本文的范围。有很多关于flexbison的书籍和文档。你在开始研究gram.y 里给出的语法之前应该对bison很熟悉,否则你将看不懂那里面的内容, 理解不了发生了什么事情。

46.3.2. 转换处理

分析器阶段只使用和 SQL 语法结构相关的固定规则创建一个分析树。它不会查找任何系统表, 因此就不可能理解请求操作里详细的语义。在分析器阶段完成之后, 转换处理接受分析器传过来的分析树然后进行语义解析,解析查询中引用了哪些表、 哪些函数、哪些操作符。最终生成表示这些信息的数据结构,称之为查询树

把裸分析(raw parsing)和语义分析分成两个过程的原因是系统表查找只能在一个事务中进行, 而不想在一接收到查询字符串就发起一个事务。裸分析阶段已经足够可以标识事务控制命令( BEGINROLLBACK等),并且这些东西不用任何进一步的分析就可以执行。 一旦知道正在处理一个真正的查询(比如SELECTUPDATE), 就可以启动一个事务(如果尚未启动一个事务的话),只有这个时候转换处理才可以被调用。

转换处理生成的查询树在结构上与裸分析树很相似,但是在细节上有很多区别。 比如,在分析树里的FuncCall节点代表那些看上去像函数调用的东西。 根据引用的名字是一个普通函数还是一个聚合函数,这个可能被转换成一个FuncExprAggref节点。同样,有关字段和表达式结果的具体数据类型也添加到查询树中。