PG重写流程

SQL执行流程

执行SQL语句,分为两个大的阶段:优化和执行。这里主要介绍优化相关的东西。优化又分为几个阶段:

  •  词法解析:生成Token
  •  语法解析:生成语法树
  •  语义分析:PG中主要是拿元数据,处理gp_rewite的重写规则
  •  优化:把逻辑操作符树,转化为可以执行的,由物理操作符组成的执行计划,实际上也是一颗树。

语义分析

在PG中,会把语法树,转化为一个称为Query的结构体,这是一个中间形态,可以理解为一个上下文,为进一步操作做准备。在这个阶段,PG做了两件事:

  • transform:获取必要的元数据,把语法树的节点,转化为更方便操作的数据结构,形成一颗新的树。
  • rewrite: 一个主要的工作,是从pg_rewite中获取规则,并应用规则。

rewrite

CREATE RULE

<重写规范>

sql

CREATE [ OR REPLACE ] RULE name AS ON event

    TO table_name [ WHERE condition ]

    DO [ ALSO | INSTEAD ] { NOTHING | command | ( command ; command ... ) }

其中 event 可以是以下之一:

    SELECT | INSERT | UPDATE | DELETE

  • CREATE RULE定义一条应用于指定表或视图的规则。
  • CREATE OR REPLACE RULE将创建一条新规则或者替换同一个表上具有同一名称的现有规则。

PostgreSQL规则系统允许我们定义 针对数据库表中插入、更新或者删除动作上的替代动作。当在一个给定表上执行给定命令时,会有几种情况:

  • 触发执行指定的命令。
  • INSTEAD规则可以用另一个命令替换给定的命令
  • 禁止一个命令的执行。
  • 实现Sql视图

sql

create rule r1 as on update to test DO INSTEAD NOTHING;

select * from pg_rewrite where rulename = 'r1';

oid   | rulename | ev_class | ev_type | ev_enabled | is_instead | ev_qual |

24576 | r1       |    16385 | 2       | O          | t          | <>      |

pg_rewrite

pg_rewrite系统目录表存储表和视图的重写规则。如果一个表在这个目录中有任何规则,其pg_class.relhasrules必须为真。

可以看到,CREATE RULE创建的规则,被存放到了pg_rewrite表中。

postgres 中重写的实现

上面说的语义分析的第一个阶段,在PG中被称为transform,这个阶段的总入口为:pg_analyze_and_rewrite。

parse_analyze:会把语法树,转化为合适的数据结构,放入Query中

  •     表表达式转化为RangeTblEntry
  •     列-->ColRef

pg_rewrite_query:一个主要的工作,是应用pg_rewrite中的规则。

在PG里面,一个关系的元数据,为了高效的获取,会被缓存起来,用`RelationData`数据结构管理起来,这里面有个对象:`rd_rules`,是用来管理这个表的重写规则的。这个数据结构由函数`RelationBuildRuleLock`初始化。下面是关键的初始化代码:
 

    /*

     * open pg_rewrite and begin a scan

     *

     * Note: since we scan the rules using RewriteRelRulenameIndexId, we will

     * be reading the rules in name order, except possibly during

     * emergency-recovery operations (ie, IgnoreSystemIndexes). This in turn

     * ensures that rules will be fired in name order.

     */

    rewrite_desc = table_open(RewriteRelationId, AccessShareLock);

    rewrite_tupdesc = RelationGetDescr(rewrite_desc);

    rewrite_scan = systable_beginscan(rewrite_desc,

                                      RewriteRelRulenameIndexId,

                                      true, NULL,

                                      1, &key);



    while (HeapTupleIsValid(rewrite_tuple = systable_getnext(rewrite_scan)))

    {

        ...



        rule = (RewriteRule *) MemoryContextAlloc(rulescxt,

                                                  sizeof(RewriteRule));



        rule->ruleId = rewrite_form->oid;



        rule->event = rewrite_form->ev_type - '0';

        rule->enabled = rewrite_form->ev_enabled;

        rule->isInstead = rewrite_form->is_instead;



        rule_datum = heap_getattr(rewrite_tuple,

                                  Anum_pg_rewrite_ev_action,

                                  rewrite_tupdesc,

                                  &isnull);



        rule_datum = heap_getattr(rewrite_tuple,

                                  Anum_pg_rewrite_ev_qual,

                                  rewrite_tupdesc,

                                  &isnull);



        **rule_str = TextDatumGetCString(rule_datum);**



        rule->qual = (Node *) stringToNode(rule_str);



        ......



        rules[numlocks++] = rule;

    }



    /*

     * end the scan and close the attribute relation

     */

    systable_endscan(rewrite_scan);

    table_close(rewrite_desc, AccessShareLock);



    /*

     * form a RuleLock and insert into relation

     */

    rulelock = (RuleLock *) MemoryContextAlloc(rulescxt, sizeof(RuleLock));

    rulelock->numLocks = numlocks;

    rulelock->rules = rules;



    relation->rd_rules = rulelock;

现在可以做规则的应用工作了:fireRules

    foreach(l, locks)

    {

        RewriteRule *rule_lock = (RewriteRule *) lfirst(l);



        ......



        /* Now process the rule's actions and add them to the result list */

        foreach(r, actions)

        {

            Query      *rule_action = lfirst(r);



            if (rule_action->commandType == CMD_NOTHING)

                continue;



            rule_action = rewriteRuleAction(parsetree, rule_action,

                                            event_qual, rt_index, event,

                                            returning_flag);



            ......



            results = lappend(results, rule_action);

        }

    }

上面的逻辑中,`locks`实际上就是从`RelationData`中取出来的,最后由`rewriteRuleAction`,应用规则

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值