图片来源:https://momjian.us/main/writings/pgsql/src_flow.pdf
重写阶段主要进行的是一些语义上的重写替换。经典的操作是对视图view的查询进行重写。比如:
图片来源:http://www.interdb.jp/pg/pgsql03.html
postgres重写器定义了一套rule system,对insert、update、delete、select四类语句进行重写
文档:http://www.postgres.cn/docs/11/rules.html
源码框架如下
QueryRewrite (rewrite/rewriteHandler.c)
|->RewriteQuery (*) (查询重写,获得querylist)
|->foreach(l, querylist)
| |->fireRIRrules (*)
| |->(设置queryId)
|->(在query list中查找并设置可以set tag的query)
RewriteQuery (rewrite/rewriteHandler.c)
|->foreach(lc1, parsetree->cteList) (处理WITH子句中的所有CTE)
| |->(如果CTE是SELECT,则直接跳过不处理)
| |->RewriteQuery (*) (重写CTE中的查询)
| |->(用重写后的query覆盖CTE中的查询,对CTE,当前只支持单条语句的DO INSTEAD规则,其他情况都报错)
|->(如果查询语句不是SELECT和UTILITY)
| |->rt_fetch (parser/parsetree.h) (获得resultRelation对应的RTE)
| |->table_open (access/table/table.c)
| |->(对不同语句类型做分别处理:重写targetList)
| | |*->(CMD_INSERT)
| | | |->(如果有VALUES,则获得其对应的RTE)
| | | |->if (values_rte)
| | | |*->(有VALUES对应的RTE)
| | | | |->rewriteTargetListIU (*) (重写INSERT/UPDATE的targetList)
| | | | |->rewriteValuesRTE (*) (重写VALUES,把DEFAULT变成缺省值表达式)
| | | |*->rewriteTargetListIU (*)
| | |*->(CMD_UPDATE)
| | | |->rewriteTargetListIU (*)
| | | |->rewriteTargetListUD (*) (重写UPDATE/DELETE的targetList)
| | |*->(CMD_DELETE)
| | | |->rewriteTargetListUD (*)
| | |*->(其他)
| | |->(报错)
| |->matchLocks (*) (获得匹配的规则,规则保存在RelationData结构中的rd_rules,其类型是RuleLock(rewrite/prs2lock.h))
| |->fireRules (*)
| |->if(没有INSTEAD规则,并且是个视图,该视图没有INSTEAD触发器) (该视图必须是可更新视图)
| | |->rewriteTargetView (*) (如果不是可更新视图则报错)
| | |->(把原来的query加到product_queries,加在前面或者后面)
| | |->(把instead和returning设为true)
| |->if (product_queries != NIL) (product_queries是在fireRules函数中生成的所有规则的动作语句)
| | |->(首先检查规则是否递归了)
| | |->(创建rewritten_event,并添加到列表rewritten_events的开头)
| | |->foreach(n, product_queries) (重写规则中的动作语句)
| | | |->RewriteQuery (*)
| | | |->(把重写结果加到rewritten列表中)
| | |->(从rewritten_events的开头删除rewritten_event)
| |->(如果有INSTEAD规则并且原始查询有RETURNING子句,而规则动作中没有RETURNING,则报错)
| |->heap_close (access/heap/heapam.c)
|->if (!instead) (如果没有unqualified INSTEAD规则)
| |->if (parsetree->commandType == CMD_INSERT)
| | |*->(把quad_product或者原来的query添加到rewritten列表的开头)
| | |*->(把quad_product或者原来的query添加到rewritten列表的结尾)
|->(如果重写结果包括多个非utility语句,并且原来的query中有CTE则报错)
fireRIRrules (rewrite/rewriteHandler.c)
|->while (rt_index < list_length(parsetree->rtable)) (处理每个RTE)
| |->rt_fetch (parser/parsetree.h)
| |->(如果是RTE_SUBQUERY)
| | |->fireRIRrules (*)
| | |->(continue)
| |->(如果不是RTE_RELATION,则跳过不处理)
| |->(如果是物化视图,则跳过不处理)
| |->(跳过没有在查询中引用到的RTE)
| |->(跳过在ApplyRetrieveRule中新增加的RTE)
| |->table_open (access/table/table.c)
| |->(收集所有SELECT规则)
| |->if (locks != NIL) (收集到的SELECT规则)
| | |->(检查是否有无穷递归)
| | |->foreach(l, locks) (处理每个规则)
| | | |->ApplyRetrieveRule (*)
| |->heap_close (access/heap/heapam.c)
|->foreach(lc, parsetree->cteList) (处理每个CTE)
| |->fireRIRrules (*)
|->if (parsetree->hasSubLinks)
| |->query_tree_walker (nodes/nodeFuncs.c) (fireRIRonSubLink (*))
ApplyRetrieveRule (rewrite/rewriteHandler.c)
|->(检查各种无效情况)
|->if (rt_index == parsetree->resultRelation) (可更新视图,已经经过rewriteTargetView处理)
| |->
|->get_parse_rowmark (parser/parse_relation.c)
|->AcquireRewriteLocks (*)
|->fireRIRrules (*)
|->(把对rule_action的fireRIRrule的结果作为子查询挂到当前RTE下)
|->markQueryForLocking (*)