查询重写模块前接查询分析模块,后接查询优化模块。对于从查询分析模块传递过来的原始查询树链表,查询重写模块会一个个地分析。对于单个查询树,它先判断这个查询树是由功能性语句还是由查询语句构造而来,在确定了语句类型后,又会有细分的操作分支。
pg_rewrite_query() 函数体现了这个功能,这个函数也是查询重写模块的入口函数,对于这个函数,我写了一篇博客进行介绍:
在这个函数中,被用来实现重写功能的函数主要是 QueryRewrite(),而当查询树不被重写时, pg_rewrite_query() 函数就会调用 list_make1() 来对查询树作进一步的处理,对于这两个函数,我也做了解析:
说到 QueryRewrite() 函数,它用三步来处理一个可重写的查询树,首先它用 RewriteQuery() 只对由 INSERT/DELETE/UPDATE 语句构造而来的查询树进行重写,之后使用 fireRIRrules() 对由 SELECT 语句构造而来的查询树进行重写,最后主要是将查询重写后的查询树链表返回。
之后,我又对 RewriteQuery() 和 fireRIRrules() 进行了解析:
RewriteQuery() 中,首先是对 CTE 的重写,然后利用范围表对结果进一步处理。fireRIRrules() 中,先用 while 循环来遍历该查询树的所有范围表,每通过 rt_fetch() 获得一个范围表的地址,就判断它的类型,根据它的类型进行相应操作。之后,打开范围表获取关系,再根据关系获取作用于这些关系的规则,应用这些规则去重写查询树,如果存在 WITH 子句,调用 fireRIRrules() 对 WITH 子句进行重写操作,如果查询树有子链接,那么对它们进行遍历,并使用 fireRIRonSubLink() 函数进行重写处理,最终也是调用 fireRIRrules() 函数来完成重写工作。