Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

Example Analysis of query rewriting in PostgreSQL

2025-02-24 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Database >

Share

Shulou(Shulou.com)05/31 Report--

Editor to share with you the example analysis of query rewriting in PostgreSQL, I believe that most people do not know much about it, so share this article for your reference, I hope you can learn a lot after reading this article, let's go to know it!

Rewritten Query structure

III. Source code interpretation

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) / / enter query tree {List * querytree_list; if (Debug_print_parse) / / debug mode, output parse tree tree elog_node_display (LOG, "parse tree", query, Debug_pretty_print); if (log_parser_stats) ResetUsage () If (query- > commandType = = CMD_UTILITY) / / tool statement {/ * don't rewrite utilities, just dump'em into result list * / querytree_list = list_make1 (query);} else// non-tool statement {/ * rewrite regular queries * / querytree_list = QueryRewrite (query) / / enter query rewriting} 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) / / enter query tree {uint64 input_query_id = parsetree- > queryId;// query id List * querylist;// query tree, intermediate result List * results;// final result ListCell * lnterbank / temporary variable CmdType origCmdType;// command type 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 * step 1: apply all non-SELECT rules (UPDATE/INSERT, etc.). Query does not need to be executed * / 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 * step 2, apply all RIR rules * RIR is the abbreviation of Retrieve-Instead-Retrieve, The name is based on history.RETRIEVE was the PostQUEL keyword * for what you know as SELECT. A rule fired ona RETRIEVE event, that is an unconditional INSTEAD rule * with exactly one RETRIEVE action is called RIR-rule. * / results = NIL; foreach (l, querylist) / / Loop {Query * query = (Query *) lfirst (l); / / get Query query = fireRIRrules (query, NIL); / / apply RIR rule query- > queryId = input_query_id;// setting query id results = lappend (results, query) / / add to the list of returned results} / * * Step 3 * * step 3, determine which Query sets the command result label, and update the canSetTag fields * 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 RIRrules on each rangetable entry in the given query * apply all RIR rules on each RTE * * 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- > index ListCell * lc;// temporary variable of resultRelation;// result Relation int rt_index;//RTE / * * 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) / / Loop {RangeTblEntry * rte;//RTE Relation rel;// relation List * locks;// Lock list RuleLock * rules;// Rule Lock RewriteRule * rule;// rewrite Rule int iBack / temporary comparison there + + rt_index;// Index + 1 rte = rt_fetch (rt_index, parsetree- > rtable) / / get 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) / / subquery {rte- > subquery = fireRIRrules (rte- > subquery, activeRIRs); / / Recursive processing continue;} / * * Joins and other non-relation RTEs can be ignored completely. * / if (rte- > rtekind! = RTE_RELATION) / / non-RELATION does not need to deal with 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 of the materialized view class does not need to deal with 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 does not need to deal with 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)) / / the corresponding RTE is NULL, and there is no need to deal with 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) / / result relationship continue; / * * We can use NoLock here since either the parser or * AcquireRewriteLocks should have locked the rel already. * / rel = heap_open (rte- > relid, NoLock); / / get "relationship" according to relid / * * Collect the RIR rules that we must apply * / rules = rel- > rd_rules;// get the rule if (rules! = NULL) {locks = NIL; for (I = 0; I)

< rules->

< list_length(parsetree->

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Database

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report