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中查询重写的示例分析"这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注行业资讯频道!
查询
规则
处理
结果
应用
语句
分析
篇文章
递归
循环
检查
示例
元素
内容
变量
命令
工具
类型
结构
视图
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
千方百计数据库对接
网络安全与攻击防御
获取数据库表中所有数据
军民融合数据库
安全客网站服务器TCP端口
网络安全十八大
安徽双线服务器
微信助手车机版连不上服务器
计算机网络技术计算机应用
vps服务器kaivps
服务器配置与管理课程标准
网络技术运营维护
京华品博睿网络技术有限公司
kodi安装国内服务器
上下班打卡数据库怎么做
近日网络安全会议
关系型数据库基本操作
怎么共享数据库
淳安租房软件开发
算命软件开发
北京网络技术质量服务
文件服务器 权限和安全
数据库代码集合大全
软件开发需规法律法规
网络部关于网络安全的请示
重庆涪陵网上生鲜软件开发
淮安软件开发费用是多少
苹果 文件服务器
创业年代中的服务器开发
我国网络安全的由来