PostgreSQL源码#2-4(query rewrite)_java

图片来源:https://momjian.us/main/writings/pgsql/src_flow.pdf


重写阶段主要进行的是一些语义上的重写替换。经典的操作是对视图view的查询进行重写。比如:


PostgreSQL源码#2-4(query rewrite)_java_02

图片来源: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 (*)