44.3. 分析器阶段

分析器阶段含两个部分:

44.3.1. 分析器

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

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

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

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

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

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

44.3.2. 转换处理

分析器阶段只使用和 SQL 语法结构相关的固定规则创建一个分析树。 它不会查找任何系统表,因此就不可能理解请求查询里面的详细的语意。 在分析器技术之后,转换处理接受分析器(transformation process) 传过来的分析树然后做进一步处理, 解析哪些查询中引用了哪个表、哪个函数、哪个操作符的语意。 所生成的表示这个信息的数据结构叫做查询树(query tree)。

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

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