forked from huawei/openGauss-server
enter
This commit is contained in:
parent
5445b2c69b
commit
d03d910cf9
|
|
@ -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_varnos)不能完全包含在旧节点的关系标识集合(old_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
|
||||
|
|
|
|||
Loading…
Reference in New Issue