0
点赞
收藏
分享

微信扫一扫

PostgreSQL数据库查询——QueryRewrite


在pg_rewrite表中保存的是一个字符串形式的节点,通过stringtonode和nodetostring两个函数,将元数据表中的字符串转为相应的node类型的数据,这样就可以使用该node对象来替换query树中相应的节点。

src/backend/rewrite/rewriteHandler.c

PostgreSQL数据库查询——QueryRewrite_字符串

QueryRewrite函数是重写器的主入口。
第一步,应用所有非select规则
第二步,对每个查询应用所有RIR规则
第三步,判定查询结果支持设置command-result标签,然后更新canSetTag域。如果原先的查询还在LIST中,设置command tag。否则,最后相同种类的INSTEAD查询被允许设置tag。

/* 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;
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 */
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 */
results = NIL;
foreach(l, querylist) {
Query *query = (Query *) lfirst(l);
query = fireRIRrules(query, NIL);
query->queryId = input_query_id;
results = lappend(results, query);
}

/* Step 3
* 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;
}


举报

相关推荐

0 条评论