This commit is contained in:
Cachuela 2023-09-29 23:12:55 +08:00
parent 5445b2c69b
commit d03d910cf9
1 changed files with 173 additions and 100 deletions

273
src/gausskernel/optimizer/prep/prepjointree.cpp Executable file → Normal file
View File

@ -127,35 +127,42 @@ static bool contains_swctes(const PlannerInfo *root);
* Unlike most other functions in this file, this function doesn't recurse;
* we rely on other processing to invoke it on sub-queries at suitable times.
*/
/*
SET操作的顶层
*/
void replace_empty_jointree(Query *parse)
{
RangeTblEntry *rte;
Index rti;
RangeTblRef *rtr;
RangeTblEntry *rte; // 声明一个RangeTblEntry结构体指针用于表示查询范围表条目
Index rti; // 声明一个索引,用于表示范围表条目的索引
RangeTblRef *rtr; // 声明一个RangeTblRef结构体指针用于表示范围表引用
/* Nothing to do if jointree is already nonempty */
/* 如果联接树jointree已经不为空就不需要做任何操作 */
if (parse->jointree->fromlist != NIL)
return;
/* We mustn't change it in the top level of a setop tree, either */
/* 如果在SET操作的顶层我们也不能更改它 */
if (parse->setOperations)
return;
/* Create suitable RTE */
rte = makeNode(RangeTblEntry);
rte->rtekind = RTE_RESULT;
rte->eref = makeAlias("*RESULT*", NIL);
/* 创建适当的范围表条目RangeTblEntry */
rte = makeNode(RangeTblEntry); // 创建一个新的范围表条目
rte->rtekind = RTE_RESULT; // 设置范围表条目的类型为RTE_RESULT
rte->eref = makeAlias("*RESULT*", NIL); // 为范围表条目创建一个别名为"*RESULT*"
/* Add it to rangetable */
parse->rtable = lappend(parse->rtable, rte);
rti = list_length(parse->rtable);
/* 将范围表条目添加到范围表中 */
parse->rtable = lappend(parse->rtable, rte); // 将新创建的范围表条目添加到查询解析树的范围表中
rti = list_length(parse->rtable); // 获取新添加的范围表条目的索引
/* And jam a reference into the jointree */
rtr = makeNode(RangeTblRef);
rtr->rtindex = rti;
parse->jointree->fromlist = list_make1(rtr);
/* 并且将一个范围表引用插入到联接树中 */
rtr = makeNode(RangeTblRef); // 创建一个新的范围表引用
rtr->rtindex = rti; // 设置范围表引用的索引为新添加的范围表条目的索引
parse->jointree->fromlist = list_make1(rtr); // 将范围表引用添加到查询解析树的联接树中
}
#ifndef ENABLE_MULTIPLE_NODES
/*
* helper function to check if SWCB ctes contaisn in current SubQuery, normally help us to
@ -163,25 +170,29 @@ void replace_empty_jointree(Query *parse)
*/
static bool contains_swctes(const PlannerInfo *root)
{
// 如果查询解析树为空或者其中的CTE列表为空返回false
if (root->parse == NULL || root->parse->cteList == NIL) {
return false;
}
List *cteList = root->parse->cteList;
ListCell *lc = NULL;
bool found = false;
foreach(lc, cteList) {
CommonTableExpr *cte = (CommonTableExpr *)lfirst(lc);
List *cteList = root->parse->cteList; // 获取查询解析树中的CTE列表
ListCell *lc = NULL; // 声明一个用于遍历列表的列表元素指针
bool found = false; // 声明一个布尔值用于表示是否找到特定类型的CTE
/* check if cte from parse->ctelist is a swcb converted */
// 遍历CTE列表
foreach(lc, cteList) {
CommonTableExpr *cte = (CommonTableExpr *)lfirst(lc); // 获取当前CTE
/* 检查parse->ctelist中的CTE是否是swcb转换的 */
if (cte->swoptions != NULL) {
found = true;
break;
found = true; // 如果CTE中包含swoptions将found设置为true
break; // 跳出循环因为已经找到了符合条件的CTE
}
}
return found;
return found; // 返回是否找到特定类型的CTE的结果
}
#endif
/*
@ -277,35 +288,42 @@ void pull_up_sublinks(PlannerInfo* root)
*/
Node* assign_qual_clause(Node* new_node, Node* old_node, Node* qual, Relids old_node_relids)
{
// 如果限定条件qual为空则直接返回新节点new_node无需处理
if (qual == NULL) {
return new_node;
}
// 从限定条件中获取相关的变量编号varnos
Relids qual_varnos = pull_varnos(qual);
/*
* We need add this quals to new_node if old_node_relids can not include qual_varnos.
* than can happend when or_clause pull up.
* qual_varnosold_node_relids
* new_node
* OR条件的上升处理中
*/
if (!bms_is_subset(qual_varnos, old_node_relids)) {
if (IsA(new_node, FromExpr)) {
((FromExpr*)new_node)->quals = qual;
((FromExpr*)new_node)->quals = qual; // 将限定条件设置为新节点的条件
} else {
new_node = (Node*)makeFromExpr(list_make1(new_node), qual);
new_node = (Node*)makeFromExpr(list_make1(new_node), qual); // 创建一个新的FromExpr节点并将限定条件添加到其中
}
}
/* Only need put qual to old node, this qual can be original(pull up before) qual.*/
/* 否则,只需要将限定条件放在旧节点上,这个限定条件可能是原始的(在上升之前已经存在的)限定条件。 */
else {
if (IsA(old_node, FromExpr)) {
((FromExpr*)old_node)->quals = qual;
((FromExpr*)old_node)->quals = qual; // 将限定条件设置为旧节点的条件
} else {
((JoinExpr*)old_node)->quals = qual;
((JoinExpr*)old_node)->quals = qual; // 将限定条件设置为联接节点的条件
}
}
// 释放变量编号集合的内存
bms_free_ext(qual_varnos);
return new_node;
return new_node; // 返回处理后的新节点
}
/*
* Recurse through jointree nodes for pull_up_sublinks()
*
@ -506,12 +524,12 @@ static Node* pull_up_sublinks_jointree_recurse(PlannerInfo* root, Node* jtnode,
static Node* pull_up_sublinks_qual_recurse(PlannerInfo* root, Node* node, Node** jtlink1, Relids *available_rels1,
Node** jtlink2, Relids *available_rels2, Node* all_quals)
{
if (node == NULL)
if (node == NULL)// 如果传入的节点为空直接返回NULL
return NULL;
if (IsA(node, SubLink)) {
SubLink* sublink = (SubLink*)node;
JoinExpr* j = NULL;
Relids child_rels;
if (IsA(node, SubLink)) {// 如果节点是一个子查询SubLink
SubLink* sublink = (SubLink*)node;// 将节点转换为子查询结构体
JoinExpr* j = NULL;// 声明一个JoinExpr结构体指针用于表示连接表达式
Relids child_rels;// 用于存储子查询关联的关系标识集合
if (has_no_expand_hint((Query*)sublink->subselect)) {
return node;
@ -685,12 +703,13 @@ static Node* pull_up_sublinks_qual_recurse(PlannerInfo* root, Node* node, Node**
ListCell* l = NULL;
foreach (l, ((BoolExpr*)node)->args) {
Node* oldclause = (Node*)lfirst(l);
Node* newclause = NULL;
Node* oldclause = (Node*)lfirst(l);// 获取当前参数作为旧的子句
Node* newclause = NULL;// 用于存储处理后的新子句
// 调用递归函数处理当前子句
newclause = pull_up_sublinks_qual_recurse(
root, oldclause, jtlink1, available_rels1, jtlink2, available_rels2, all_quals);
if (newclause != NULL)
// 如果处理后的新子句不为空
if (newclause != NULL)// 将新子句添加到新子句列表中
newclauses = lappend(newclauses, newclause);
}
/* We might have got back fewer clauses than we started with */
@ -834,29 +853,34 @@ static Node* pull_up_sublinks_targetlist(PlannerInfo *root,
*/
void inline_set_returning_functions(PlannerInfo* root)
{
ListCell* rt = NULL;
ListCell* rt = NULL; // 声明一个用于遍历查询的范围表条目的列表元素指针
// 遍历查询解析树的范围表条目
foreach (rt, root->parse->rtable) {
RangeTblEntry* rte = (RangeTblEntry*)lfirst(rt);
RangeTblEntry* rte = (RangeTblEntry*)lfirst(rt); // 获取当前范围表条目
// 如果范围表条目的类型是函数RTE_FUNCTION
if (rte->rtekind == RTE_FUNCTION) {
Query* funcquery = NULL;
Query* funcquery = NULL; // 用于存储函数展开后的查询
/* Check safety of expansion, and expand if possible */
/* 检查展开的安全性,并在可能的情况下进行展开 */
funcquery = inline_set_returning_function(root, rte);
// 如果成功展开函数
if (funcquery != NULL) {
/* Successful expansion, replace the rtable entry */
/* 成功展开替换范围表条目的类型为子查询RTE_SUBQUERY */
rte->rtekind = RTE_SUBQUERY;
rte->subquery = funcquery;
rte->funcexpr = NULL;
rte->funccoltypes = NIL;
rte->funccoltypmods = NIL;
rte->funccolcollations = NIL;
rte->subquery = funcquery; // 将展开后的查询存储在范围表条目中
rte->funcexpr = NULL; // 清空函数表达式
rte->funccoltypes = NIL; // 清空函数列类型列表
rte->funccoltypmods = NIL; // 清空函数列类型修改列表
rte->funccolcollations = NIL; // 清空函数列的字符集列表
}
}
}
}
/*
* This recursively processes the jointree and returns a modified jointree.
*/
@ -1530,18 +1554,20 @@ static Node* pull_up_simple_union_all(PlannerInfo* root, Node* jtnode, RangeTblE
static void pull_up_union_leaf_queries(
Node* setOp, PlannerInfo* root, int parentRTindex, Query* setOpQuery, int childRToffset)
{
// 如果 setOp 是 RangeTblRef 类型
if (IsA(setOp, RangeTblRef)) {
RangeTblRef* rtr = (RangeTblRef*)setOp;
RangeTblRef* rtr = (RangeTblRef*)setOp; // 将 setOp 转换为 RangeTblRef 结构体
int childRTindex;
AppendRelInfo* appinfo = NULL;
/*
* Calculate the index in the parent's range table
*
*/
childRTindex = childRToffset + rtr->rtindex;
/*
* Build a suitable AppendRelInfo, and attach to parent's list.
* AppendRelInfo
*/
appinfo = makeNode(AppendRelInfo);
appinfo->parent_relid = parentRTindex;
@ -1553,29 +1579,35 @@ static void pull_up_union_leaf_queries(
root->append_rel_list = lappend(root->append_rel_list, appinfo);
/*
* Recursively apply pull_up_subqueries to the new child RTE. (We
* must build the AppendRelInfo first, because this will modify it.)
* Note that we can pass NULL for containing-join info even if we're
* actually under an outer join, because the child's expressions
* aren't going to propagate up above the join.
* pull_up_subqueries_recurse RTE
* AppendRelInfo
* 使 NULL
*
*/
rtr = makeNode(RangeTblRef);
rtr->rtindex = childRTindex;
(void)pull_up_subqueries_recurse(root, (Node*)rtr, NULL, NULL, appinfo);
} else if (IsA(setOp, SetOperationStmt)) {
}
// 如果 setOp 是 SetOperationStmt 类型
else if (IsA(setOp, SetOperationStmt)) {
SetOperationStmt* op = (SetOperationStmt*)setOp;
/* Recurse to reach leaf queries */
/* 递归处理左子查询 */
pull_up_union_leaf_queries(op->larg, root, parentRTindex, setOpQuery, childRToffset);
/* 递归处理右子查询 */
pull_up_union_leaf_queries(op->rarg, root, parentRTindex, setOpQuery, childRToffset);
} else {
}
// 如果 setOp 是未知的节点类型
else {
ereport(ERROR,
(errmodule(MOD_OPT),
errcode(ERRCODE_UNRECOGNIZED_NODE_TYPE),
errmsg("unrecognized node type: %d", (int)nodeTag(setOp))));
errmsg("未知的节点类型: %d", (int)nodeTag(setOp))));
}
}
/*
* make_setop_translation_list
* Build the list of translations from parent Vars to child Vars for
@ -1585,21 +1617,26 @@ static void pull_up_union_leaf_queries(
*/
static void make_setop_translation_list(Query* query, Index newvarno, List** translated_vars)
{
List* vars = NIL;
ListCell* l = NULL;
List* vars = NIL; // 声明一个用于存储变量的列表
ListCell* l = NULL; // 声明一个用于遍历目标列表的列表元素指针
// 遍历查询的目标列表
foreach (l, query->targetList) {
TargetEntry* tle = (TargetEntry*)lfirst(l);
TargetEntry* tle = (TargetEntry*)lfirst(l); // 获取当前目标条目
// 如果目标条目被标记为 "resjunk",则跳过它,不处理
if (tle->resjunk)
continue;
// 创建一个新的变量,表示目标条目,并将其添加到变量列表中
vars = lappend(vars, makeVarFromTargetEntry(newvarno, tle));
}
// 将构建的变量列表赋值给传入的 translated_vars 指针
*translated_vars = vars;
}
/*
* is_simple_lateral_subquery
* If the subquery is LATERAL, check for pullup restrictions from that.
@ -1660,7 +1697,7 @@ static bool is_simple_lateral_subquery(Query* subquery, JoinExpr *lowest_outer_j
static bool is_grouping_subquery(Query* subquery)
{
/*
/*
* Can't pull up a subquery involving grouping, aggregation, sorting,
* limiting, or WITH. (XXX WITH could possibly be allowed later)
*
@ -1670,14 +1707,20 @@ static bool is_grouping_subquery(Query* subquery)
* that case the locking was originally declared in the upper query
* anyway.
*/
// 如果子查询中包含聚合函数hasAggs、窗口函数hasWindowFuncs、GROUP BY 子句groupClause
// GROUPING SETS 子句groupingSets、HAVING 子句havingQual、排序子句sortClause
// DISTINCT 子句distinctClause、LIMIT 偏移limitOffset、LIMIT 计数limitCount
// FOR UPDATE 子句hasForUpdate或者通用表达式列表cteList则认为它不是分组子查询。
if (subquery->hasAggs || subquery->hasWindowFuncs || subquery->groupClause || subquery->groupingSets ||
subquery->havingQual || subquery->sortClause || subquery->distinctClause || subquery->limitOffset ||
subquery->limitCount || subquery->hasForUpdate || subquery->cteList)
return false;
// 如果上述条件都不满足,则认为子查询是分组子查询。
return true;
}
/*
* is_simple_subquery
* Check a subquery in the range table to see if it's simple enough
@ -1788,64 +1831,72 @@ static bool is_simple_union_all(Query* subquery)
{
SetOperationStmt* topop = NULL;
/* Let's just make sure it's a valid subselect ... */
/* 首先确保子查询是一个有效的子查询... */
if (!IsA(subquery, Query) || subquery->commandType != CMD_SELECT || subquery->utilityStmt != NULL)
ereport(
ERROR, (errmodule(MOD_OPT), errcode(ERRCODE_OPTIMIZER_INCONSISTENT_STATE), (errmsg("subquery is bogus"))));
ERROR, (errmodule(MOD_OPT), errcode(ERRCODE_OPTIMIZER_INCONSISTENT_STATE), (errmsg("子查询无效"))));
/* Is it a set-operation query at all? */
/* 子查询是否是一个集合操作查询? */
topop = (SetOperationStmt*)subquery->setOperations;
if (topop == NULL)
return false;
AssertEreport(
IsA(topop, SetOperationStmt), MOD_OPT_REWRITE, "subquery's setOperations mismatch in is_simple_union_all");
IsA(topop, SetOperationStmt), MOD_OPT_REWRITE, "is_simple_union_all 中子查询的 setOperations 不匹配");
#ifndef ENABLE_MULTIPLE_NODES
// 如果子查询包含 ROWNUM 过滤条件,就不是简单的 UNION ALL 查询
if (ContainRownumQual(subquery)) {
return false;
}
#endif
/* Can't handle ORDER BY, LIMIT/OFFSET, locking, or WITH */
/* 不能处理包含 ORDER BY、LIMIT/OFFSET、锁定或 WITH 子句的子查询 */
if (subquery->sortClause || subquery->limitOffset || subquery->limitCount || subquery->rowMarks ||
subquery->cteList)
return false;
/* Recursively check the tree of set operations */
/* 递归检查集合操作树 */
return is_simple_union_all_recurse((Node*)topop, subquery, topop->colTypes);
}
static bool is_simple_union_all_recurse(Node* setOp, Query* setOpQuery, List* colTypes)
{
// 如果当前节点是 RangeTblRef 类型
if (IsA(setOp, RangeTblRef)) {
RangeTblRef* rtr = (RangeTblRef*)setOp;
RangeTblEntry* rte = rt_fetch(rtr->rtindex, setOpQuery->rtable);
Query* subquery = rte->subquery;
RangeTblRef* rtr = (RangeTblRef*)setOp; // 将当前节点转换为 RangeTblRef 结构体
RangeTblEntry* rte = rt_fetch(rtr->rtindex, setOpQuery->rtable); // 获取当前节点对应的范围表条目
Query* subquery = rte->subquery; // 获取范围表条目中的子查询
AssertEreport(subquery != NULL, MOD_OPT_REWRITE, "subquery should not be NULL in is_simple_union_all_recurse");
AssertEreport(subquery != NULL, MOD_OPT_REWRITE, "is_simple_union_all_recurse 中的子查询不应为 NULL");
/* Leaf nodes are OK if they match the toplevel column types */
/* We don't have to compare typmods or collations here */
/* 如果是叶子节点,需要检查其列类型是否与顶层查询的列类型匹配 */
/* 我们不必在这里比较类型修饰符typmods或字符集collations */
return tlist_same_datatypes(subquery->targetList, colTypes, true);
} else if (IsA(setOp, SetOperationStmt)) {
SetOperationStmt* op = (SetOperationStmt*)setOp;
}
// 如果当前节点是 SetOperationStmt 类型
else if (IsA(setOp, SetOperationStmt)) {
SetOperationStmt* op = (SetOperationStmt*)setOp; // 将当前节点转换为 SetOperationStmt 结构体
/* Must be UNION ALL */
/* 必须是 UNION ALL 操作 */
if (op->op != SETOP_UNION || !op->all)
return false;
/* Recurse to check inputs */
/* 递归检查左子树和右子树 */
return is_simple_union_all_recurse(op->larg, setOpQuery, colTypes) &&
is_simple_union_all_recurse(op->rarg, setOpQuery, colTypes);
} else {
}
// 如果当前节点是未知的节点类型
else {
ereport(ERROR,
(errmodule(MOD_OPT),
errcode(ERRCODE_UNRECOGNIZED_NODE_TYPE),
errmsg("unrecognized node type: %d", (int)nodeTag(setOp))));
return false; /* keep compiler quiet */
errmsg("未知的节点类型: %d", (int)nodeTag(setOp))));
return false; /* 使编译器保持安静 */
}
}
/*
* is_safe_append_member
* Check a subquery that is a leaf of a UNION ALL appendrel to see if it's
@ -1897,34 +1948,33 @@ jointree_contains_lateral_outer_refs(Node *jtnode, bool restricted,
if (jtnode == NULL)
return false;
if (IsA(jtnode, RangeTblRef))
return false;
return false; // 如果当前节点是范围表引用节点,不包含外部引用,返回 false
else if (IsA(jtnode, FromExpr))
{
FromExpr *f = (FromExpr *) jtnode;
ListCell *l = NULL;
/* First, recurse to check child joins */
/* 首先递归检查子联接 */
foreach(l, f->fromlist)
{
if (jointree_contains_lateral_outer_refs((Node *)lfirst(l),
restricted,
safe_upper_varnos))
return true;
return true; // 如果子联接包含外部引用,返回 true
}
/* Then check the top-level quals */
/* 然后检查顶层条件表达式 */
if (restricted &&
!bms_is_subset(pull_varnos_of_level(f->quals, 1),
safe_upper_varnos))
return true;
return true; // 如果条件表达式中包含外部引用,且不在安全的上级变量范围内,返回 true
}
else if (IsA(jtnode, JoinExpr))
{
JoinExpr *j = (JoinExpr *) jtnode;
/*
* If this is an outer join, we mustn't allow any upper lateral
* references in or below it.
*
*/
if (j->jointype != JOIN_INNER)
{
@ -1932,28 +1982,29 @@ jointree_contains_lateral_outer_refs(Node *jtnode, bool restricted,
safe_upper_varnos = NULL;
}
/* Check the child joins */
/* 检查子联接 */
if (jointree_contains_lateral_outer_refs(j->larg,
restricted,
safe_upper_varnos))
return true;
return true; // 如果左子联接包含外部引用,返回 true
if (jointree_contains_lateral_outer_refs(j->rarg,
restricted,
safe_upper_varnos))
return true;
return true; // 如果右子联接包含外部引用,返回 true
/* Check the JOIN's qual clauses */
/* 检查联接的条件表达式 */
if (restricted &&
!bms_is_subset(pull_varnos_of_level(j->quals, 1),
safe_upper_varnos))
return true;
return true; // 如果条件表达式中包含外部引用,且不在安全的上级变量范围内,返回 true
}
else
elog(ERROR, "unrecognized node type: %d",
elog(ERROR, "未识别的节点类型: %d",
(int) nodeTag(jtnode));
return false;
}
/*
* Helper routine for pull_up_subqueries: do pullup_replace_vars on every
* expression in the jointree, without changing the jointree structure itself.
@ -2057,10 +2108,20 @@ static void replace_vars_in_jointree(Node* jtnode, pullup_replace_vars_context*
*/
static Node* pullup_replace_vars(Node* expr, pullup_replace_vars_context* context)
{
// 使用 replace_rte_variables 函数替换表达式中的变量
// 参数说明:
// expr待替换的表达式
// context->varno用于替换的范围表索引
// 0替换的层级深度0 表示替换所有层级)
// pullup_replace_vars_callback用于处理替换的回调函数
// (void*)context回调函数的上下文数据
// context->outer_hasSubLinks是否包含子查询链接在外部查询中
return replace_rte_variables(
expr, context->varno, 0, pullup_replace_vars_callback, (void*)context, context->outer_hasSubLinks);
}
static Node* pullup_replace_vars_callback(Var* var, replace_rte_variables_context* context)
{
pullup_replace_vars_context* rcon = (pullup_replace_vars_context*)context->callback_arg;
@ -2220,7 +2281,18 @@ static Query *
pullup_replace_vars_subquery(Query *query,
pullup_replace_vars_context *context)
{
// 确保输入的 query 是一个有效的 Query 结构
Assert(IsA(query, Query));
// 使用 replace_rte_variables 函数替换子查询中的变量
// 参数说明:
// (Node *) query待替换的子查询
// context->varno用于替换的范围表索引
// 1替换的层级深度1 表示只替换一层,即子查询中的变量)
// pullup_replace_vars_callback用于处理替换的回调函数
// (void *) context回调函数的上下文数据
// NULL不包含子查询链接在外部查询中
return (Query *) replace_rte_variables((Node *) query,
context->varno, 1,
pullup_replace_vars_callback,
@ -2228,6 +2300,7 @@ pullup_replace_vars_subquery(Query *query,
NULL);
}
/*
* flatten_simple_union_all
* Try to optimize top-level UNION ALL structure into an appendrel