50.3. 分析器阶段

50.3.1. 分析器
50.3.2. 转换处理

分析器阶段由两部分组成:

50.3.1. 分析器

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

词法分析器定义在文件scan.l中,并负责识别标识符SQL关键词等。对于找到的每一个关键词或标识符将生成一个记号并返回给语法分析器。

语法分析器定义在gram.y文件中,它由一组语法规则动作,动作将在规则被触发时被执行。动作的代码(实际上是C代码)将被用于构建分析树。

程序flex把文件scan.l转换成C源文件scan.c, 程序bison把文件gram.y转换为gram.c。在这些转换结束后,一个正规的C编译器就可以用于创建分析器。绝不要对生成的C文件做任何修改,因为每次flexbison被调用都会重写它们。

注意

前面提到的转换和编译通常是由随PostgreSQL源代码发布的makefiles自动完成。

对于bison的详细介绍或者gram.y中的语法规则超出了本文的范围。有很多书籍和文档介绍flexbison。在学习gram.y中的语法之前你应该先熟悉bison,否则你将无法理解发生了什么。

50.3.2. 转换处理

分析阶段根据SQL的语法结构的固定规则创建一个分析树。它不会在系统目录做任何查找,这样它不可能了解所请求的操作的详细语义。在分析器完成之后,转换处理接手分析器返还的树,并进行语义解释来理解该查询引用了哪些表、函数和操作符。用于表示该信息的数据结构被称为查询树

将原始分析从语义分析中分离出来的原因是系统目录的查找只能在一个事务中完成,而我们不希望在收到一个查询字符串时立即开始一个事务。原始分析阶段足以识别事务控制命令(BEGINROLLBACK等),并且这些可以在没有任何进一步分析之前正确地被执行。一旦我们知道我们正在处理一个确切的查询(例如SELECTUPDATE),就可以开始一个事务(如果我们还不在其中)。只有到这时转换处理才能被调用。

由转换处理创建的查询树在结构上和原始分析树有很多地方相似,但是在细节上有很多不同之处。例如,分析树中的一个FuncCall节点表示某些在语法上看起来像一个函数调用的东西。它可能被转换成一个FuncExprAggref节点,取决于被引用的名字是一个普通函数或是一个聚集函数。此外,关于列和表达式结果的实际数据类型的信息被加入到了查询树中。