温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

PostgreSQL中查询重写的示例分析

发布时间:2021-11-10 15:01:46 来源:亿速云 阅读:184 作者:小新 栏目:关系型数据库

小编给大家分享一下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.xm from vw_dwxx dw inner join t_grxx gr  on dw.dwbh = gr.dwbh where dw.dwbh = '1001';

启动gdb,跟踪调试:

(gdb) b QueryRewrite Breakpoint 1 at 0x80a85e: file rewriteHandler.c, line 3571. (gdb) c Continuing. Breakpoint 1, QueryRewrite (parsetree=0x2868820) at rewriteHandler.c:3571 3571        uint64      input_query_id = parsetree->queryId; (gdb) n 3590        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) step fireRIRrules (parsetree=0x2868820, activeRIRs=0x0) at rewriteHandler.c:1721 1721        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) n 1830                        rule = lfirst(l); (gdb)  1832                        parsetree = ApplyRetrieveRule(parsetree, (gdb) step ApplyRetrieveRule (parsetree=0x2868820, rule=0x2947298, rt_index=1, relation=0x7f57a6b90be8,      activeRIRs=0x29320e8) at rewriteHandler.c:1462 ... #进入ApplyRetrieveRule调用fireRIRrules 1581        rule_action = fireRIRrules(rule_action, activeRIRs); (gdb) step fireRIRrules (parsetree=0x2970118, activeRIRs=0x29320e8) at rewriteHandler.c:1721 1721        int         origResultRelation = parsetree->resultRelation; ... (gdb) finish #结束ApplyRetrieveRule->fireRIRrules的调用 Run till exit from #0  fireRIRrules (parsetree=0x2970118, activeRIRs=0x29320e8) at rewriteHandler.c:1788 0x00000000008079cf in ApplyRetrieveRule (parsetree=0x2868820, rule=0x2947298, rt_index=1,      relation=0x7f57a6b90be8, activeRIRs=0x29320e8) at rewriteHandler.c:1581 1581        rule_action = fireRIRrules(rule_action, activeRIRs); Value returned is $56 = (Query *) 0x2970118 ... #重写为子查询 (gdb) n 1589        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) n 1590        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) finish Run till exit from #0  ApplyRetrieveRule (parsetree=0x2868820, rule=0x2947298, rt_index=1,      relation=0x7f57a6b90be8, activeRIRs=0x29320e8) at rewriteHandler.c:1601 0x0000000000807fe3 in fireRIRrules (parsetree=0x2868820, activeRIRs=0x29320e8) at rewriteHandler.c:1832 1832                        parsetree = ApplyRetrieveRule(parsetree, Value returned is $60 = (Query *) 0x2868820 (gdb) n 1828                    foreach(l, locks) (gdb)  1839                    activeRIRs = list_delete_first(activeRIRs); (gdb)  1843            heap_close(rel, NoLock); #RIR处理完毕 (gdb) p activeRIRs $61 = (List *) 0x0 (gdb) finish Run till exit from #0  fireRIRrules (parsetree=0x2868820, activeRIRs=0x0) at rewriteHandler.c:1843 0x000000000080a8b5 in QueryRewrite (parsetree=0x2868820) at rewriteHandler.c:3604 3604            query = fireRIRrules(query, NIL); Value returned is $62 = (Query *) 0x2868820 (gdb) finish Run till exit from #0  0x000000000080a8b5 in QueryRewrite (parsetree=0x2868820) at rewriteHandler.c:3604 0x000000000084c945 in pg_rewrite_query (query=0x2868820) at postgres.c:759 759         querytree_list = QueryRewrite(query); Value returned is $63 = (List *) 0x29320e8 (gdb) c Continuing. #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中查询重写的示例分析”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注亿速云行业资讯频道!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI