千家信息网

PostgreSQL中查询重写的示例分析

发表于:2025-11-12 作者:千家信息网编辑
千家信息网最后更新 2025年11月12日,小编给大家分享一下PostgreSQL中查询重写的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!重写后的Query
千家信息网最后更新 2025年11月12日PostgreSQL中查询重写的示例分析

小编给大家分享一下PostgreSQL中查询重写的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!

重写后的Query结构

三、源码解读

pg_rewrite_query

 /*  * Perform rewriting of a query produced by parse analysis.  *  * Note: query must just have come from the parser, because we do not do  * AcquireRewriteLocks() on it.  */ static List * pg_rewrite_query(Query *query) //输入查询树 {     List       *querytree_list;      if (Debug_print_parse) //debug模式,输出parse tree树         elog_node_display(LOG, "parse tree", query,                           Debug_pretty_print);      if (log_parser_stats)         ResetUsage();      if (query->commandType == CMD_UTILITY) //工具类语句     {         /* don't rewrite utilities, just dump 'em into result list */         querytree_list = list_make1(query);     }     else//非工具类语句     {         /* rewrite regular queries */         querytree_list = QueryRewrite(query); //进入查询重写     }      if (log_parser_stats)         ShowUsage("REWRITER STATISTICS");  #ifdef COPY_PARSE_PLAN_TREES     /* Optional debugging check: pass querytree output through copyObject() */     {         List       *new_list;          new_list = copyObject(querytree_list);         /* This checks both copyObject() and the equal() routines... */         if (!equal(new_list, querytree_list))             elog(WARNING, "copyObject() failed to produce equal parse tree");         else             querytree_list = new_list;     } #endif      if (Debug_print_rewritten)         elog_node_display(LOG, "rewritten parse tree", querytree_list,                           Debug_pretty_print);      return querytree_list; }

QueryRewrite

/*  * QueryRewrite -  *    Primary entry point to the query rewriter.  *    Rewrite one query via query rewrite system, possibly returning 0  *    or many queries.  *  * NOTE: the parsetree must either have come straight from the parser,  * or have been scanned by AcquireRewriteLocks to acquire suitable locks.  */ List * QueryRewrite(Query *parsetree) //输入查询树 {     uint64      input_query_id = parsetree->queryId;//查询id     List       *querylist;//查询树,中间结果     List       *results;//最终结果     ListCell   *l;//临时变量     CmdType     origCmdType;//命令类型     bool        foundOriginalQuery;     Query      *lastInstead;      /*      * This function is only applied to top-level original queries      */     Assert(parsetree->querySource == QSRC_ORIGINAL);     Assert(parsetree->canSetTag);      /*      * Step 1      *      * Apply all non-SELECT rules possibly getting 0 or many queries      * 第1步,应用所有非SELECT规则(UPDATE/INSERT等),查询不需要执行      */     querylist = RewriteQuery(parsetree, NIL);      /*      * Step 2      *      * Apply all the RIR rules on each query      *      * This is also a handy place to mark each query with the original queryId      * 第2步,应用所有RIR规则      * RIR是Retrieve-Instead-Retrieve的缩写,The name is based on history.RETRIEVE was the PostQUEL keyword       * for what you know as SELECT. A rule fired on a RETRIEVE event, that is an unconditional INSTEAD rule       * with exactly one RETRIEVE action is called RIR-rule.      */     results = NIL;     foreach(l, querylist) //循环     {         Query      *query = (Query *) lfirst(l);//获取Query          query = fireRIRrules(query, NIL);//应用RIR规则          query->queryId = input_query_id;//设置查询id          results = lappend(results, query);//加入返回结果列表中     }      /*      * Step 3      *      * 第3步,确定哪一个Query设置命令结果标签,并更新canSetTag字段      * Determine which, if any, of the resulting queries is supposed to set      * the command-result tag; and update the canSetTag fields accordingly.      *       *      * If the original query is still in the list, it sets the command tag.      * Otherwise, the last INSTEAD query of the same kind as the original is      * allowed to set the tag.  (Note these rules can leave us with no query      * setting the tag.  The tcop code has to cope with this by setting up a      * default tag based on the original un-rewritten query.)      *      * The Asserts verify that at most one query in the result list is marked      * canSetTag.  If we aren't checking asserts, we can fall out of the loop      * as soon as we find the original query.      */     origCmdType = parsetree->commandType;     foundOriginalQuery = false;     lastInstead = NULL;      foreach(l, results)     {         Query      *query = (Query *) lfirst(l);          if (query->querySource == QSRC_ORIGINAL)         {             Assert(query->canSetTag);             Assert(!foundOriginalQuery);             foundOriginalQuery = true; #ifndef USE_ASSERT_CHECKING             break; #endif         }         else         {             Assert(!query->canSetTag);             if (query->commandType == origCmdType &&                 (query->querySource == QSRC_INSTEAD_RULE ||                  query->querySource == QSRC_QUAL_INSTEAD_RULE))                 lastInstead = query;         }     }      if (!foundOriginalQuery && lastInstead != NULL)         lastInstead->canSetTag = true;      return results; }

fireRIRrules

 /*  * fireRIRrules -  *  Apply all RIR rules on each rangetable entry in the given query  *  在每一个RTE上应用所有的RIR规则  *  * activeRIRs is a list of the OIDs of views we're already processing RIR  * rules for, used to detect/reject recursion.  */ static Query * fireRIRrules(Query *parsetree, List *activeRIRs) {     int         origResultRelation = parsetree->resultRelation;//结果Relation     int         rt_index;//RTE的index     ListCell   *lc;//临时变量      /*      * don't try to convert this into a foreach loop, because rtable list can      * get changed each time through...      */     rt_index = 0;     while (rt_index < list_length(parsetree->rtable)) //循环     {         RangeTblEntry *rte;//RTE         Relation    rel;//关系         List       *locks;//锁列表         RuleLock   *rules;//规则锁         RewriteRule *rule;//重写规则         int         i;//临时比那里          ++rt_index;//索引+1          rte = rt_fetch(rt_index, parsetree->rtable);//获取RTE          /*          * A subquery RTE can't have associated rules, so there's nothing to          * do to this level of the query, but we must recurse into the          * subquery to expand any rule references in it.          */         if (rte->rtekind == RTE_SUBQUERY)//子查询         {             rte->subquery = fireRIRrules(rte->subquery, activeRIRs);//递归处理             continue;         }          /*          * Joins and other non-relation RTEs can be ignored completely.          */         if (rte->rtekind != RTE_RELATION)//非RTE_RELATION无需处理             continue;          /*          * Always ignore RIR rules for materialized views referenced in          * queries.  (This does not prevent refreshing MVs, since they aren't          * referenced in their own query definitions.)          *          * Note: in the future we might want to allow MVs to be conditionally          * expanded as if they were regular views, if they are not scannable.          * In that case this test would need to be postponed till after we've          * opened the rel, so that we could check its state.          */         if (rte->relkind == RELKIND_MATVIEW)//物化视图类的Relation无需处理             continue;          /*          * In INSERT ... ON CONFLICT, ignore the EXCLUDED pseudo-relation;          * even if it points to a view, we needn't expand it, and should not          * because we want the RTE to remain of RTE_RELATION type.  Otherwise,          * it would get changed to RTE_SUBQUERY type, which is an          * untested/unsupported situation.          */         if (parsetree->onConflict &&             rt_index == parsetree->onConflict->exclRelIndex)//INSERT ... ON CONFLICT 无需处理             continue;          /*          * If the table is not referenced in the query, then we ignore it.          * This prevents infinite expansion loop due to new rtable entries          * inserted by expansion of a rule. A table is referenced if it is          * part of the join set (a source table), or is referenced by any Var          * nodes, or is the result table.          */         if (rt_index != parsetree->resultRelation &&             !rangeTableEntry_used((Node *) parsetree, rt_index, 0))//相应的RTE为NULL,无需处理             continue;          /*          * Also, if this is a new result relation introduced by          * ApplyRetrieveRule, we don't want to do anything more with it.          */         if (rt_index == parsetree->resultRelation &&             rt_index != origResultRelation)//结果关系             continue;          /*          * We can use NoLock here since either the parser or          * AcquireRewriteLocks should have locked the rel already.          */         rel = heap_open(rte->relid, NoLock);//根据relid获取"关系"          /*          * Collect the RIR rules that we must apply          */         rules = rel->rd_rules;//获取关系上的规则         if (rules != NULL)         {             locks = NIL;             for (i = 0; i < rules->numLocks; i++)             {                 rule = rules->rules[i];//获取规则                 if (rule->event != CMD_SELECT)                     continue;//非SELECT类型,继续下一个规则                  locks = lappend(locks, rule);//添加到列表中             }              /*              * If we found any, apply them --- but first check for recursion!              */             if (locks != NIL)             {                 ListCell   *l;                  if (list_member_oid(activeRIRs, RelationGetRelid(rel)))//检查是否存在递归                     ereport(ERROR,                             (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),                              errmsg("infinite recursion detected in rules for relation \"%s\"",                                     RelationGetRelationName(rel))));                 activeRIRs = lcons_oid(RelationGetRelid(rel), activeRIRs);//                  foreach(l, locks)//循环                 {                     rule = lfirst(l);                      parsetree = ApplyRetrieveRule(parsetree,                                                   rule,                                                   rt_index,                                                   rel,                                                   activeRIRs);//应用规则                 }                  activeRIRs = list_delete_first(activeRIRs);//删除已应用的规则             }         }          heap_close(rel, NoLock);//释放资源     }      /* Recurse into subqueries in WITH */     foreach(lc, parsetree->cteList) //WITH 语句处理     {         CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc);          cte->ctequery = (Node *)             fireRIRrules((Query *) cte->ctequery, activeRIRs);     }      /*      * Recurse into sublink subqueries, too.  But we already did the ones in      * the rtable and cteList.      */     if (parsetree->hasSubLinks) //存在子链接         query_tree_walker(parsetree, fireRIRonSubLink, (void *) activeRIRs,                           QTW_IGNORE_RC_SUBQUERIES);      /*      * Apply any row level security policies.  We do this last because it      * requires special recursion detection if the new quals have sublink      * subqueries, and if we did it in the loop above query_tree_walker would      * then recurse into those quals a second time.      */     rt_index = 0;     foreach(lc, parsetree->rtable)//应用行级安全策略     {         RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);         Relation    rel;         List       *securityQuals;         List       *withCheckOptions;         bool        hasRowSecurity;         bool        hasSubLinks;          ++rt_index;          /* Only normal relations can have RLS policies */         if (rte->rtekind != RTE_RELATION ||             (rte->relkind != RELKIND_RELATION &&              rte->relkind != RELKIND_PARTITIONED_TABLE))             continue;          rel = heap_open(rte->relid, NoLock);          /*          * Fetch any new security quals that must be applied to this RTE.          */         get_row_security_policies(parsetree, rte, rt_index,                                   &securityQuals, &withCheckOptions,                                   &hasRowSecurity, &hasSubLinks);          if (securityQuals != NIL || withCheckOptions != NIL)         {             if (hasSubLinks)             {                 acquireLocksOnSubLinks_context context;                  /*                  * Recursively process the new quals, checking for infinite                  * recursion.                  */                 if (list_member_oid(activeRIRs, RelationGetRelid(rel)))                     ereport(ERROR,                             (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),                              errmsg("infinite recursion detected in policy for relation \"%s\"",                                     RelationGetRelationName(rel))));                  activeRIRs = lcons_oid(RelationGetRelid(rel), activeRIRs);                  /*                  * get_row_security_policies just passed back securityQuals                  * and/or withCheckOptions, and there were SubLinks, make sure                  * we lock any relations which are referenced.                  *                  * These locks would normally be acquired by the parser, but                  * securityQuals and withCheckOptions are added post-parsing.                  */                 context.for_execute = true;                 (void) acquireLocksOnSubLinks((Node *) securityQuals, &context);                 (void) acquireLocksOnSubLinks((Node *) withCheckOptions,                                               &context);                  /*                  * Now that we have the locks on anything added by                  * get_row_security_policies, fire any RIR rules for them.                  */                 expression_tree_walker((Node *) securityQuals,                                        fireRIRonSubLink, (void *) activeRIRs);                  expression_tree_walker((Node *) withCheckOptions,                                        fireRIRonSubLink, (void *) activeRIRs);                  activeRIRs = list_delete_first(activeRIRs);             }              /*              * Add the new security barrier quals to the start of the RTE's              * list so that they get applied before any existing barrier quals              * (which would have come from a security-barrier view, and should              * get lower priority than RLS conditions on the table itself).              */             rte->securityQuals = list_concat(securityQuals,                                              rte->securityQuals);              parsetree->withCheckOptions = list_concat(withCheckOptions,                                                       parsetree->withCheckOptions);         }          /*          * Make sure the query is marked correctly if row level security          * applies, or if the new quals had sublinks.          */         if (hasRowSecurity)             parsetree->hasRowSecurity = true;         if (hasSubLinks)             parsetree->hasSubLinks = true;          heap_close(rel, NoLock);     }      return parsetree;//返回 }

ApplyRetrieveRule

  * ApplyRetrieveRule - expand an ON SELECT rule  */ static Query * ApplyRetrieveRule(Query *parsetree,//查询树                   RewriteRule *rule,//重写规则                   int rt_index,//RTE index                   Relation relation,//关系                   List *activeRIRs)//RIR链表 {     Query      *rule_action;     RangeTblEntry *rte,                *subrte;//RTE     RowMarkClause *rc;      if (list_length(rule->actions) != 1)         elog(ERROR, "expected just one rule action");     if (rule->qual != NULL)         elog(ERROR, "cannot handle qualified ON SELECT rule");      if (rt_index == parsetree->resultRelation) //目标关系?     {         /*          * We have a view as the result relation of the query, and it wasn't          * rewritten by any rule.  This case is supported if there is an          * INSTEAD OF trigger that will trap attempts to insert/update/delete          * view rows.  The executor will check that; for the moment just plow          * ahead.  We have two cases:          *          * For INSERT, we needn't do anything.  The unmodified RTE will serve          * fine as the result relation.          *          * For UPDATE/DELETE, we need to expand the view so as to have source          * data for the operation.  But we also need an unmodified RTE to          * serve as the target.  So, copy the RTE and add the copy to the          * rangetable.  Note that the copy does not get added to the jointree.          * Also note that there's a hack in fireRIRrules to avoid calling this          * function again when it arrives at the copied RTE.          */         if (parsetree->commandType == CMD_INSERT)             return parsetree;         else if (parsetree->commandType == CMD_UPDATE ||                  parsetree->commandType == CMD_DELETE)         {             RangeTblEntry *newrte;             Var        *var;             TargetEntry *tle;              rte = rt_fetch(rt_index, parsetree->rtable);             newrte = copyObject(rte);             parsetree->rtable = lappend(parsetree->rtable, newrte);             parsetree->resultRelation = list_length(parsetree->rtable);              /*              * There's no need to do permissions checks twice, so wipe out the              * permissions info for the original RTE (we prefer to keep the              * bits set on the result RTE).              */             rte->requiredPerms = 0;             rte->checkAsUser = InvalidOid;             rte->selectedCols = NULL;             rte->insertedCols = NULL;             rte->updatedCols = NULL;              /*              * For the most part, Vars referencing the view should remain as              * they are, meaning that they implicitly represent OLD values.              * But in the RETURNING list if any, we want such Vars to              * represent NEW values, so change them to reference the new RTE.              *              * Since ChangeVarNodes scribbles on the tree in-place, copy the              * RETURNING list first for safety.              */             parsetree->returningList = copyObject(parsetree->returningList);             ChangeVarNodes((Node *) parsetree->returningList, rt_index,                            parsetree->resultRelation, 0);              /*              * To allow the executor to compute the original view row to pass              * to the INSTEAD OF trigger, we add a resjunk whole-row Var              * referencing the original RTE.  This will later get expanded              * into a RowExpr computing all the OLD values of the view row.              */             var = makeWholeRowVar(rte, rt_index, 0, false);             tle = makeTargetEntry((Expr *) var,                                   list_length(parsetree->targetList) + 1,                                   pstrdup("wholerow"),                                   true);              parsetree->targetList = lappend(parsetree->targetList, tle);              /* Now, continue with expanding the original view RTE */         }         else             elog(ERROR, "unrecognized commandType: %d",                  (int) parsetree->commandType);     }         /*      * Check if there's a FOR [KEY] UPDATE/SHARE clause applying to this view.      * 检查是否有FOR UPDATE/SHARE语句      * Note: we needn't explicitly consider any such clauses appearing in      * ancestor query levels; their effects have already been pushed down to      * here by markQueryForLocking, and will be reflected in "rc".      */     rc = get_parse_rowmark(parsetree, rt_index);      /*      * Make a modifiable copy of the view query, and acquire needed locks on      * the relations it mentions.  Force at least RowShareLock for all such      * rels if there's a FOR [KEY] UPDATE/SHARE clause affecting this view.      */     //copy规则,上锁     rule_action = copyObject(linitial(rule->actions));      AcquireRewriteLocks(rule_action, true, (rc != NULL));      /*      * If FOR [KEY] UPDATE/SHARE of view, mark all the contained tables as      * implicit FOR [KEY] UPDATE/SHARE, the same as the parser would have done      * if the view's subquery had been written out explicitly.      */     if (rc != NULL)         markQueryForLocking(rule_action, (Node *) rule_action->jointree,                             rc->strength, rc->waitPolicy, true);      /*      * Recursively expand any view references inside the view.      * 递归展开      * Note: this must happen after markQueryForLocking.  That way, any UPDATE      * permission bits needed for sub-views are initially applied to their      * RTE_RELATION RTEs by markQueryForLocking, and then transferred to their      * OLD rangetable entries by the action below (in a recursive call of this      * routine).      */     rule_action = fireRIRrules(rule_action, activeRIRs);      /*      * Now, plug the view query in as a subselect, replacing the relation's      * original RTE.      */     rte = rt_fetch(rt_index, parsetree->rtable);//获取原RTE      rte->rtekind = RTE_SUBQUERY;//转换为子查询     rte->relid = InvalidOid;//设置为0     rte->security_barrier = RelationIsSecurityView(relation);     rte->subquery = rule_action;//子查询设置为刚才构造的Query     rte->inh = false;           /* must not be set for a subquery */      /*      * We move the view's permission check data down to its rangetable. The      * checks will actually be done against the OLD entry therein.      */     subrte = rt_fetch(PRS2_OLD_VARNO, rule_action->rtable);//OLD RTE仍需要检查权限     Assert(subrte->relid == relation->rd_id);     subrte->requiredPerms = rte->requiredPerms;     subrte->checkAsUser = rte->checkAsUser;     subrte->selectedCols = rte->selectedCols;     subrte->insertedCols = rte->insertedCols;     subrte->updatedCols = rte->updatedCols;      rte->requiredPerms = 0;     /* no permission check on subquery itself */     rte->checkAsUser = InvalidOid;     rte->selectedCols = NULL;     rte->insertedCols = NULL;     rte->updatedCols = NULL;      return parsetree;//返回结果 }

四、跟踪分析

SQL语句:

testdb=# select dw.dwmc,gr.grbh,gr.xmfrom vw_dwxx dw inner join t_grxx gr on dw.dwbh = gr.dwbhwhere dw.dwbh = '1001';

启动gdb,跟踪调试:

(gdb) b QueryRewriteBreakpoint 1 at 0x80a85e: file rewriteHandler.c, line 3571.(gdb) cContinuing.Breakpoint 1, QueryRewrite (parsetree=0x2868820) at rewriteHandler.c:35713571        uint64      input_query_id = parsetree->queryId;(gdb) n3590        querylist = RewriteQuery(parsetree, NIL);#parsetree查询树#rtable有3个元素(RTE),查询重写注意处理这3个RTE(gdb) p *parsetree$6 = {type = T_Query, commandType = CMD_SELECT, querySource = QSRC_ORIGINAL, queryId = 0, canSetTag = true,   utilityStmt = 0x0, resultRelation = 0, hasAggs = false, hasWindowFuncs = false, hasTargetSRFs = false,   hasSubLinks = false, hasDistinctOn = false, hasRecursive = false, hasModifyingCTE = false,   hasForUpdate = false, hasRowSecurity = false, cteList = 0x0, rtable = 0x2868be0, jointree = 0x2962180,   targetList = 0x2961db8, override = OVERRIDING_NOT_SET, onConflict = 0x0, returningList = 0x0,   groupClause = 0x0, groupingSets = 0x0, havingQual = 0x0, windowClause = 0x0, distinctClause = 0x0,   sortClause = 0x0, limitOffset = 0x0, limitCount = 0x0, rowMarks = 0x0, setOperations = 0x0,   constraintDeps = 0x0, withCheckOptions = 0x0, stmt_location = 0, stmt_len = 110}(gdb) p *parsetree->rtable$7 = {type = T_List, length = 3, head = 0x2868bc0, tail = 0x2961bb8}(gdb) 3604            query = fireRIRrules(query, NIL);(gdb) stepfireRIRrules (parsetree=0x2868820, activeRIRs=0x0) at rewriteHandler.c:17211721        int         origResultRelation = parsetree->resultRelation;(gdb) n...1729        rt_index = 0;(gdb) 1730        while (rt_index < list_length(parsetree->rtable))1741            rte = rt_fetch(rt_index, parsetree->rtable);(gdb) 1748            if (rte->rtekind == RTE_SUBQUERY)#第1个RTE,视图vw_dwxx#rtekind = RTE_RELATION, relid = 16403, relkind = 118 'v'(gdb) p *rte$12 = {type = T_RangeTblEntry, rtekind = RTE_RELATION, relid = 16403, relkind = 118 'v', tablesample = 0x0,   subquery = 0x0, security_barrier = false, jointype = JOIN_INNER, joinaliasvars = 0x0, functions = 0x0,   funcordinality = false, tablefunc = 0x0, values_lists = 0x0, ctename = 0x0, ctelevelsup = 0,   self_reference = false, coltypes = 0x0, coltypmods = 0x0, colcollations = 0x0, enrname = 0x0,   enrtuples = 0, alias = 0x2867f08, eref = 0x2868a40, lateral = false, inh = true, inFromCl = true,   requiredPerms = 2, checkAsUser = 0, selectedCols = 0x29614e8, insertedCols = 0x0, updatedCols = 0x0,   securityQuals = 0x0}1796            rel = heap_open(rte->relid, NoLock);(gdb) 1801            rules = rel->rd_rules;#关系Relation(gdb) p *rel$13 = {rd_node = {spcNode = 1663, dbNode = 16384, relNode = 16403}, rd_smgr = 0x0, rd_refcnt = 1,   rd_backend = -1, rd_islocaltemp = false, rd_isnailed = false, rd_isvalid = true, rd_indexvalid = 0 '\000',   rd_statvalid = false, rd_createSubid = 0, rd_newRelfilenodeSubid = 0, rd_rel = 0x7f57a6b90df8,   rd_att = 0x7f57a6b90f08, rd_id = 16403, rd_lockInfo = {lockRelId = {relId = 16403, dbId = 16384}},   rd_rules = 0x2945bc0, rd_rulescxt = 0x2947140, trigdesc = 0x0, rd_rsdesc = 0x0, rd_fkeylist = 0x0,   rd_fkeyvalid = false, rd_partkeycxt = 0x0, rd_partkey = 0x0, rd_pdcxt = 0x0, rd_partdesc = 0x0,   rd_partcheck = 0x0, rd_indexlist = 0x0, rd_oidindex = 0, rd_pkindex = 0, rd_replidindex = 0,   rd_statlist = 0x0, rd_indexattr = 0x0, rd_projindexattr = 0x0, rd_keyattr = 0x0, rd_pkattr = 0x0,   rd_idattr = 0x0, rd_projidx = 0x0, rd_pubactions = 0x0, rd_options = 0x0, rd_index = 0x0,   rd_indextuple = 0x0, rd_amhandler = 0, rd_indexcxt = 0x0, rd_amroutine = 0x0, rd_opfamily = 0x0,   rd_opcintype = 0x0, rd_support = 0x0, rd_supportinfo = 0x0, rd_indoption = 0x0, rd_indexprs = 0x0,   rd_indpred = 0x0, rd_exclops = 0x0, rd_exclprocs = 0x0, rd_exclstrats = 0x0, rd_amcache = 0x0,   rd_indcollation = 0x0, rd_fdwroutine = 0x0, rd_toastoid = 0, pgstat_info = 0x0}#rules(gdb) p *rel->rd_rules #rules是指向RewriteRule数组的指针,元素只有一个(numLocks)$15 = {numLocks = 1, rules = 0x2947268}(gdb) p *(RewriteRule *)rel->rd_rules->rules[0]$28 = {ruleId = 16406, event = CMD_SELECT, qual = 0x0, actions = 0x2945b90, enabled = 79 'O',   isInstead = true}#查看rules中的actions链表(gdb) p *rel->rd_rules->rules[0]->actions$31 = {type = T_List, length = 1, head = 0x2945b70, tail = 0x2945b70}(gdb) p *(Node *)rel->rd_rules->rules[0]->actions->head->data.ptr_value$32 = {type = T_Query}(gdb) set $action=(Query *)rel->rd_rules->rules[0]->actions->head->data.ptr_value#重写规则中的action为Query!(gdb) p $action$34 = (Query *) 0x29472c8(gdb) p *$action$35 = {type = T_Query, commandType = CMD_SELECT, querySource = QSRC_ORIGINAL, queryId = 0, canSetTag = true,   utilityStmt = 0x0, resultRelation = 0, hasAggs = false, hasWindowFuncs = false, hasTargetSRFs = false,   hasSubLinks = false, hasDistinctOn = false, hasRecursive = false, hasModifyingCTE = false,   hasForUpdate = false, hasRowSecurity = false, cteList = 0x0, rtable = 0x2947708, jointree = 0x2945820,   targetList = 0x2945990, override = OVERRIDING_NOT_SET, onConflict = 0x0, returningList = 0x0,   groupClause = 0x0, groupingSets = 0x0, havingQual = 0x0, windowClause = 0x0, distinctClause = 0x0,   sortClause = 0x0, limitOffset = 0x0, limitCount = 0x0, rowMarks = 0x0, setOperations = 0x0,   constraintDeps = 0x0, withCheckOptions = 0x0, stmt_location = -1, stmt_len = -1}(gdb) p *$action->rtable$36 = {type = T_List, length = 3, head = 0x29476e8, tail = 0x2945800}(gdb) p *(Node *)$action->rtable->head->data.ptr_value$37 = {type = T_RangeTblEntry}(gdb) p *(RangeTblEntry *)$action->rtable->head->data.ptr_value$38 = {type = T_RangeTblEntry, rtekind = RTE_RELATION, relid = 16403, relkind = 118 'v', tablesample = 0x0,   subquery = 0x0, security_barrier = false, jointype = JOIN_INNER, joinaliasvars = 0x0, functions = 0x0,   funcordinality = false, tablefunc = 0x0, values_lists = 0x0, ctename = 0x0, ctelevelsup = 0,   self_reference = false, coltypes = 0x0, coltypmods = 0x0, colcollations = 0x0, enrname = 0x0,   enrtuples = 0, alias = 0x29474e8, eref = 0x2947588, lateral = false, inh = false, inFromCl = false,   requiredPerms = 0, checkAsUser = 10, selectedCols = 0x0, insertedCols = 0x0, updatedCols = 0x0,   securityQuals = 0x0}(gdb) p *((RangeTblEntry *)$action->rtable->head->data.ptr_value)->eref$42 = {type = T_Alias, aliasname = 0x29475b8 "old", colnames = 0x2947608}(gdb) p *((RangeTblEntry *)$action->rtable->head->next->data.ptr_value)->eref$43 = {type = T_Alias, aliasname = 0x29478c0 "new", colnames = 0x2947930}(gdb) p *((RangeTblEntry *)$action->rtable->head->next->next->data.ptr_value)->eref$44 = {type = T_Alias, aliasname = 0x2945698 "t_dwxx", colnames = 0x2945708}...1826                    activeRIRs = lcons_oid(RelationGetRelid(rel), activeRIRs);(gdb) 1828                    foreach(l, locks)(gdb) p *activeRIRs$46 = {type = T_OidList, length = 1, head = 0x29320c8, tail = 0x29320c8}(gdb) p activeRIRs->head->data.oid_value$47 = 16403#进入ApplyRetrieveRule(gdb) n1830                        rule = lfirst(l);(gdb) 1832                        parsetree = ApplyRetrieveRule(parsetree,(gdb) stepApplyRetrieveRule (parsetree=0x2868820, rule=0x2947298, rt_index=1, relation=0x7f57a6b90be8,     activeRIRs=0x29320e8) at rewriteHandler.c:1462...#进入ApplyRetrieveRule调用fireRIRrules1581        rule_action = fireRIRrules(rule_action, activeRIRs);(gdb) stepfireRIRrules (parsetree=0x2970118, activeRIRs=0x29320e8) at rewriteHandler.c:17211721        int         origResultRelation = parsetree->resultRelation;...(gdb) finish #结束ApplyRetrieveRule->fireRIRrules的调用Run till exit from #0  fireRIRrules (parsetree=0x2970118, activeRIRs=0x29320e8) at rewriteHandler.c:17880x00000000008079cf in ApplyRetrieveRule (parsetree=0x2868820, rule=0x2947298, rt_index=1,     relation=0x7f57a6b90be8, activeRIRs=0x29320e8) at rewriteHandler.c:15811581        rule_action = fireRIRrules(rule_action, activeRIRs);Value returned is $56 = (Query *) 0x2970118...#重写为子查询(gdb) n1589        rte->rtekind = RTE_SUBQUERY;(gdb) p *rte$58 = {type = T_RangeTblEntry, rtekind = RTE_RELATION, relid = 16403, relkind = 118 'v', tablesample = 0x0,   subquery = 0x0, security_barrier = false, jointype = JOIN_INNER, joinaliasvars = 0x0, functions = 0x0,   funcordinality = false, tablefunc = 0x0, values_lists = 0x0, ctename = 0x0, ctelevelsup = 0,   self_reference = false, coltypes = 0x0, coltypmods = 0x0, colcollations = 0x0, enrname = 0x0,   enrtuples = 0, alias = 0x2867f08, eref = 0x2868a40, lateral = false, inh = true, inFromCl = true,   requiredPerms = 2, checkAsUser = 0, selectedCols = 0x29614e8, insertedCols = 0x0, updatedCols = 0x0,   securityQuals = 0x0}(gdb) n1590        rte->relid = InvalidOid;(gdb) 1591        rte->security_barrier = RelationIsSecurityView(relation);(gdb) 1592        rte->subquery = rule_action;(gdb) 1593        rte->inh = false;           /* must not be set for a subquery */(gdb) 1599        subrte = rt_fetch(PRS2_OLD_VARNO, rule_action->rtable);(gdb) p *rte$59 = {type = T_RangeTblEntry, rtekind = RTE_SUBQUERY, relid = 0, relkind = 118 'v', tablesample = 0x0,   subquery = 0x2970118, security_barrier = false, jointype = JOIN_INNER, joinaliasvars = 0x0,   functions = 0x0, funcordinality = false, tablefunc = 0x0, values_lists = 0x0, ctename = 0x0,   ctelevelsup = 0, self_reference = false, coltypes = 0x0, coltypmods = 0x0, colcollations = 0x0,   enrname = 0x0, enrtuples = 0, alias = 0x2867f08, eref = 0x2868a40, lateral = false, inh = false,   inFromCl = true, requiredPerms = 2, checkAsUser = 0, selectedCols = 0x29614e8, insertedCols = 0x0,   updatedCols = 0x0, securityQuals = 0x0}...#结束ApplyRetrieveRule调用,返回上层的fireRIRrules(gdb) finishRun till exit from #0  ApplyRetrieveRule (parsetree=0x2868820, rule=0x2947298, rt_index=1,     relation=0x7f57a6b90be8, activeRIRs=0x29320e8) at rewriteHandler.c:16010x0000000000807fe3 in fireRIRrules (parsetree=0x2868820, activeRIRs=0x29320e8) at rewriteHandler.c:18321832                        parsetree = ApplyRetrieveRule(parsetree,Value returned is $60 = (Query *) 0x2868820(gdb) n1828                    foreach(l, locks)(gdb) 1839                    activeRIRs = list_delete_first(activeRIRs);(gdb) 1843            heap_close(rel, NoLock);#RIR处理完毕(gdb) p activeRIRs$61 = (List *) 0x0(gdb) finishRun till exit from #0  fireRIRrules (parsetree=0x2868820, activeRIRs=0x0) at rewriteHandler.c:18430x000000000080a8b5 in QueryRewrite (parsetree=0x2868820) at rewriteHandler.c:36043604            query = fireRIRrules(query, NIL);Value returned is $62 = (Query *) 0x2868820(gdb) finishRun till exit from #0  0x000000000080a8b5 in QueryRewrite (parsetree=0x2868820) at rewriteHandler.c:36040x000000000084c945 in pg_rewrite_query (query=0x2868820) at postgres.c:759759         querytree_list = QueryRewrite(query);Value returned is $63 = (List *) 0x29320e8(gdb) cContinuing.#DONE!

五、数据结构

RewriteRule

 /*  * RuleLock -  *    all rules that apply to a particular relation. Even though we only  *    have the rewrite rule system left and these are not really "locks",  *    the name is kept for historical reasons.  */ typedef struct RuleLock //rd_rules {     int         numLocks;     RewriteRule **rules; } RuleLock; /*  * RewriteRule -  *    holds an info for a rewrite rule  *  */ typedef struct RewriteRule {     Oid         ruleId;     CmdType     event;     Node       *qual;     List       *actions;     char        enabled;     bool        isInstead; } RewriteRule;

以上是"PostgreSQL中查询重写的示例分析"这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注行业资讯频道!

0