From 4a70a794cd22487acffeab79cdea84d3a89b8e22 Mon Sep 17 00:00:00 2001 From: Cachuela Date: Fri, 29 Sep 2023 22:20:24 +0800 Subject: [PATCH] enter --- src/gausskernel/optimizer/plan/initsplan.cpp | 293 ++++++++++--------- 1 file changed, 156 insertions(+), 137 deletions(-) diff --git a/src/gausskernel/optimizer/plan/initsplan.cpp b/src/gausskernel/optimizer/plan/initsplan.cpp index 3af8ece19..f988e241c 100644 --- a/src/gausskernel/optimizer/plan/initsplan.cpp +++ b/src/gausskernel/optimizer/plan/initsplan.cpp @@ -160,7 +160,7 @@ void build_base_rel_tlists(PlannerInfo* root, List* final_tlist)//函数用于 void add_vars_to_targetlist(PlannerInfo* root, List* vars, Relids where_needed, bool create_new_ph) { ListCell* temp = NULL; - // 断言 where_needed 不应为空�������它表示需要这些变量的关系的集合。 + // 断言 where_needed 不应为空���������它表示需要这些变量的关系的集合。 AssertEreport(!bms_is_empty(where_needed), MOD_OPT, "bms should not be null"); foreach (temp, vars) {// 遍历传入的变量列表。 @@ -237,7 +237,7 @@ extract_lateral_references(PlannerInfo *root, RelOptInfo *brel, Index rtindex) RangeTblEntry *rte = root->simple_rte_array[rtindex];// 获取与基本关系对应的 RangeTblEntry。 List *vars = NIL;// 存储原始变量引用的列表 List *newvars = NIL;// 存储处理后的变量引用的列表 - Relids where_needed = NULL; // 标识哪些关系需要哪些���量 + Relids where_needed = NULL; // 标识哪些关系需要���些���量 ListCell *lc = NULL; /* No cross-references are possible if it's not LATERAL */ @@ -498,26 +498,27 @@ void add_lateral_info(PlannerInfo *root, Index rhs, Relids lhs)//函数用于添 * clauses appearing above it. This forces those clauses to be delayed until * application of the outer join (or maybe even higher in the join tree). */ -List* deconstruct_jointree(PlannerInfo* root) +List* deconstruct_jointree(PlannerInfo* root)//函数将查询的联接树(join tree)分解为一个列表 { - List *result = NIL; - Relids qualscope = NULL; - Relids inner_join_rels = NULL; - List *postponed_qual_list = NIL; + List *result = NIL; // 用于存储分解后的联接树 + Relids qualscope = NULL; // 当前的限定范围(qualifications scope) + Relids inner_join_rels = NULL; // 内部联接的关系集合 + List *postponed_qual_list = NIL; // 存储推迟处理的限定条件的列表 - /* Start recursion at top of jointree */ + /* 开始从联接树的顶部进行递归处理 */ AssertEreport( root->parse->jointree != NULL && IsA(root->parse->jointree, FromExpr), MOD_OPT, "From expression is required."); result = deconstruct_recurse(root, (Node *) root->parse->jointree, false, &qualscope, &inner_join_rels, &postponed_qual_list); - /* Shouldn't be any leftover quals */ + /* 不应该有未处理的限定条件 */ Assert(postponed_qual_list == NIL); return result; } + /* * process_security_barrier_quals * Transfer security-barrier quals into relation's baserestrictinfo list. @@ -531,18 +532,20 @@ List* deconstruct_jointree(PlannerInfo* root) * them for purposes like equivalence class creation. Quals attached to * individual child rels will be dealt with during path creation. */ + + //函数用于处理安全障碍限定条件 + //这些限定条件通常用于实现安全性相关的筛选操作,以确保只有合适的用户可以访问数据 static void process_security_barrier_quals( PlannerInfo* root, const RangeTblEntry* rte, Relids qualscope, bool below_outer_join) { ListCell* cell1 = NULL; ListCell* cell2 = NULL; - List* quals = NIL; - Node* qual = NULL; - Index security_level = 0; + List* quals = NIL; // 存储限定条件的列表 + Node* qual = NULL; // 限定条件的表达式 + Index security_level = 0; // 安全级别 /* - * Each element of the securityQuals list has been preprocessed into an - * implicitly-ANDed list of clauses. + * 安全性限定条件列表中的每个元素都已经被预处理成了一个隐式AND连接的限定条件列表。 */ foreach (cell1, rte->securityQuals) { quals = (List*)lfirst(cell1); @@ -550,21 +553,22 @@ static void process_security_barrier_quals( foreach (cell2, quals) { qual = (Node*)lfirst(cell2); + // 将限定条件分发给相关的关系 distribute_qual_to_rels( root, qual, false, below_outer_join, JOIN_INNER, security_level, qualscope, qualscope, NULL, NULL, NULL); } /* - * All the clauses in a given sublist have the same security level, - * but successive sublists get higher levels. + * 每个子列表中的所有限定条件具有相同的安全级别,但是连续的子列表具有更高的级别。 */ security_level++; } - /* Assert that qual_security_level is higher than anything we just used */ + /* 断言限定条件的安全级别要高于我们刚刚使用的任何级别 */ Assert(security_level <= root->qualSecurityLevel); } + /* * deconstruct_recurse * One recursion level of deconstruct_jointree processing. @@ -584,28 +588,34 @@ static void process_security_barrier_quals( * * In addition, entries will be added to root->join_info_list for outer joins. */ + +/* +这段代码主要负责将查询中的关联关系和条件表达式进行递归处理, +并将它们组织成一个关联关系列表。根据不同的联接类型,处理方式有所不同, +同时也考虑了条件表达式的推迟处理 +*/ static List* deconstruct_recurse(PlannerInfo* root, Node* jtnode, bool below_outer_join, Relids* qualscope, - Relids* inner_join_rels, List **postponed_qual_list) + Relids* inner_join_rels, List **postponed_qual_list) { - List* joinlist = NIL; + List* joinlist = NIL; // 用于存储关联关系的列表 if (jtnode == NULL) { *qualscope = NULL; *inner_join_rels = NULL; - return NIL; + return NIL; // 如果 jtnode 为空,则返回空列表,表示没有关联关系 } if (IsA(jtnode, RangeTblRef)) { int varno = ((RangeTblRef*)jtnode)->rtindex; - /* No quals to deal with, just return correct result */ + /* 没有需要处理的条件表达式,直接返回正确结果 */ *qualscope = bms_make_singleton(varno); - /* Deal with any securityQuals attached to the RTE */ + /* 处理与 RTE(RangeTblEntry) 相关的安全性条件 */ if (root->qualSecurityLevel > 0) process_security_barrier_quals(root, root->simple_rte_array[varno], *qualscope, below_outer_join); - /* A single baserel does not create an inner join */ + /* 单个基表不会创建内连接 */ *inner_join_rels = NULL; - joinlist = list_make1(jtnode); + joinlist = list_make1(jtnode); // 将当前关系节点添加到关联关系列表中 } else if (IsA(jtnode, FromExpr)) { FromExpr* f = (FromExpr*)jtnode; List *child_postponed_quals = NIL; @@ -613,10 +623,8 @@ static List* deconstruct_recurse(PlannerInfo* root, Node* jtnode, ListCell* l = NULL; /* - * First, recurse to handle child joins. We collapse subproblems into - * a single joinlist whenever the resulting joinlist wouldn't exceed - * from_collapse_limit members. Also, always collapse one-element - * subproblems, since that won't lengthen the joinlist anyway. + * 首先,递归处理子关联关系。只有在结果关联关系列表不会超过 from_collapse_limit 时, + * 才会将子关联关系列表合并为一个。此外,一元子问题始终合并,因为这不会增加关联关系列表的长度。 */ *qualscope = NULL; *inner_join_rels = NULL; @@ -640,18 +648,15 @@ static List* deconstruct_recurse(PlannerInfo* root, Node* jtnode, } /* - * A FROM with more than one list element is an inner join subsuming - * all below it, so we should report inner_join_rels = qualscope. If - * there was exactly one element, we should (and already did) report - * whatever its inner_join_rels were. If there were no elements (is - * that possible?) the initialization before the loop fixed it. + * 如果 FROM 子句包含多个元素,则表示是一个包含所有下级的内连接, + * 因此我们应该报告 inner_join_rels = qualscope。如果只有一个元素,则已经报告了其内连接关系。 + * 如果没有元素(这是否可能?),则循环之前的初始化已经修复了这个问题。 */ if (list_length(f->fromlist) > 1) *inner_join_rels = *qualscope; /* - * Try to process any quals postponed by children. If they need - * further postponement, add them to my output postponed_qual_list. + * 尝试处理子关联关系推迟的任何条件表达式。如果它们需要进一步推迟,就将它们添加到输出的 postponed_qual_list 中。 */ foreach(l, child_postponed_quals) { PostponedQual *pq = (PostponedQual *) lfirst(l); @@ -667,7 +672,7 @@ static List* deconstruct_recurse(PlannerInfo* root, Node* jtnode, } /* - * Now process the top-level quals. + * 现在处理顶层条件表达式。 */ foreach (l, (List*)f->quals) { Node* qual = (Node*)lfirst(l); @@ -686,16 +691,11 @@ static List* deconstruct_recurse(PlannerInfo* root, Node* jtnode, ListCell* l = NULL; /* - * Order of operations here is subtle and critical. First we recurse - * to handle sub-JOINs. Their join quals will be placed without - * regard for whether this level is an outer join, which is correct. - * Then we place our own join quals, which are restricted by lower - * outer joins in any case, and are forced to this level if this is an - * outer join and they mention the outer side. Finally, if this is an - * outer join, we create a join_info_list entry for the join. This - * will prevent quals above us in the join tree that use those rels - * from being pushed down below this level. (It's okay for upper - * quals to be pushed down to the outer side, however.) + * 操作顺序在这里非常微妙和关键。首先,我们递归处理子 JOIN。 + * 它们的连接条件将被放置,而不考虑这个级别是否是外连接,这是正确的。 + * 然后我们放置自己的连接条件,无论如何都受到较低外连接的限制,并且如果这是外连接并且它们提到了外部,则会被强制到这个级别。 + * 最后,如果这是外连接,我们为连接创建一个 SpecialJoinInfo 条目。这将防止在连接树中我们上面的使用那些关系的条件被推送到下面。 + * (对于上面的条件被推送到外面是可以的。) */ switch (j->jointype) { case JOIN_INNER: @@ -707,7 +707,7 @@ static List* deconstruct_recurse(PlannerInfo* root, Node* jtnode, &child_postponed_quals); *qualscope = bms_union(leftids, rightids); *inner_join_rels = *qualscope; - /* Inner join adds no restrictions for quals */ + /* 内连接不会增加条件表达式的限制 */ nonnullable_rels = NULL; break; case JOIN_LEFT: @@ -732,7 +732,7 @@ static List* deconstruct_recurse(PlannerInfo* root, Node* jtnode, &child_postponed_quals); *qualscope = bms_union(leftids, rightids); *inner_join_rels = bms_union(left_inners, right_inners); - /* Semi join adds no restrictions for quals */ + /* 半连接不会增加条件表达式的限制 */ nonnullable_rels = NULL; break; case JOIN_FULL: @@ -744,30 +744,26 @@ static List* deconstruct_recurse(PlannerInfo* root, Node* jtnode, &child_postponed_quals); *qualscope = bms_union(leftids, rightids); *inner_join_rels = bms_union(left_inners, right_inners); - /* each side is both outer and inner */ + /* 每一侧都是外连接和内连接 */ nonnullable_rels = *qualscope; break; default: { - /* JOIN_RIGHT was eliminated during reduce_outer_joins() */ + /* JOIN_RIGHT 在 reduce_outer_joins() 中被消除 */ ereport(ERROR, (errmodule(MOD_OPT), errcode(ERRCODE_UNRECOGNIZED_NODE_TYPE), - errmsg("unrecognized join type in one level processing of deconstruct jointree: %d", + errmsg("在解构联接树的一个级别中,不认识的联接类型:%d", (int)j->jointype))); - nonnullable_rels = NULL; /* keep compiler quiet */ + nonnullable_rels = NULL; /* 使编译器保持安静 */ leftjoinlist = rightjoinlist = NIL; } break; } /* - * For an OJ, form the SpecialJoinInfo now, because we need the OJ's - * semantic scope (ojscope) to pass to distribute_qual_to_rels. But - * we mustn't add it to join_info_list just yet, because we don't want - * distribute_qual_to_rels to think it is an outer join below us. - * - * Semijoins are a bit of a hybrid: we build a SpecialJoinInfo, but we - * want ojscope = NULL for distribute_qual_to_rels. + * 对于外连接,现在形成 SpecialJoinInfo,因为我们需要将 OJ 的语义范围(ojscope)传递给 distribute_qual_to_rels。 + * 但我们不能立即将其添加到 join_info_list 中,因为我们不希望 distribute_qual_to_rels 认为它是在下面的外连接。 + * 半连接有点混合:我们构建了一个 SpecialJoinInfo,但我们希望 distribute_qual_to_rels 的 ojscope = NULL。 */ if (j->jointype != JOIN_INNER) { sjinfo = make_outerjoininfo(root, leftids, rightids, *inner_join_rels, @@ -782,8 +778,7 @@ static List* deconstruct_recurse(PlannerInfo* root, Node* jtnode, } /* - * Try to process any quals postponed by children. If they need - * further postponement, add them to my output postponed_qual_list. + * 尝试处理子关联关系推迟的任何条件表达式。如果它们需要进一步推迟,就将它们添加到我的输出 postponed_qual_list 中。 */ foreach(l, child_postponed_quals) { @@ -798,15 +793,14 @@ static List* deconstruct_recurse(PlannerInfo* root, Node* jtnode, else { /* - * We should not be postponing any quals past an outer join. - * If this Assert fires, pull_up_subqueries() messed up. + * 我们不应该推迟任何条件表达式到外连接之后。如果这个断言触发了,那么 pull_up_subqueries() 弄错了。 */ Assert(j->jointype == JOIN_INNER); *postponed_qual_list = lappend(*postponed_qual_list, pq); } } - /* Process the JOIN's qual clauses */ + /* 处理 JOIN 的条件表达式 */ foreach (l, (List*)j->quals) { Node* qual = (Node*)lfirst(l); @@ -823,31 +817,29 @@ static List* deconstruct_recurse(PlannerInfo* root, Node* jtnode, postponed_qual_list); } - /* Now we can add the SpecialJoinInfo to join_info_list */ + /* 现在我们可以将 SpecialJoinInfo 添加到 join_info_list 中 */ if (sjinfo != NULL) { root->join_info_list = lappend(root->join_info_list, sjinfo); - /* Each time we do that, recheck placeholder eval levels */ + /* 每次这样做时,都重新检查占位符评估级别 */ update_placeholder_eval_levels(root, sjinfo); } /* - * Finally, compute the output joinlist. We fold subproblems together - * except at a FULL JOIN or where join_collapse_limit would be - * exceeded. + * 最后,计算输出的关联关系列表。我们在 FULL JOIN 或者 join_collapse_limit 超出时合并子问题。 */ if (j->jointype == JOIN_FULL) { - /* force the join order exactly at this node */ + /* 强制在这个节点上精确地设置连接顺序 */ joinlist = list_make1(list_make2(leftjoinlist, rightjoinlist)); } else if (list_length(leftjoinlist) + list_length(rightjoinlist) <= u_sess->attr.attr_sql.join_collapse_limit) { - /* OK to combine subproblems */ + /* 可以合并子问题 */ joinlist = list_concat(leftjoinlist, rightjoinlist); } else { - /* can't combine, but needn't force join order above here */ + /* 不能合并,但不需要在这里强制连接顺序 */ Node* leftpart = NULL; Node* rightpart = NULL; - /* avoid creating useless 1-element sublists */ + /* 避免创建无用的 1 元素子列表 */ if (list_length(leftjoinlist) == 1) leftpart = (Node*)linitial(leftjoinlist); else @@ -862,28 +854,41 @@ static List* deconstruct_recurse(PlannerInfo* root, Node* jtnode, ereport(ERROR, (errmodule(MOD_OPT), errcode(ERRCODE_UNRECOGNIZED_NODE_TYPE), - errmsg("unrecognized node type in one level of deconstruct jointree: %d", (int)nodeTag(jtnode)))); - joinlist = NIL; /* keep compiler quiet */ + errmsg("在解构联接树的一个级别中,不认识的节点类型:%d", (int)nodeTag(jtnode)))); + joinlist = NIL; /* 使编译器保持安静 */ } - return joinlist; + return joinlist; // 返回关联关系列表 } + void process_security_clause_appendrel(PlannerInfo *root) { if (root->qualSecurityLevel == 0) { + // 如果当前查询的安全级别为0,表示不需要处理安全性条款,直接返回 return; } + ListCell* lc = NULL; foreach(lc, root->append_rel_list) { + // 遍历与主查询(或父查询)关联的子查询或关联关系的列表 AppendRelInfo* appinfo = (AppendRelInfo*)lfirst(lc); Index childRTindex = appinfo->child_relid; + + // 创建一个包含子查询索引的 Relids 集合,这用于标识当前处理的子查询的范围 Relids qualscope = bms_make_singleton((int)childRTindex); + + // 获取子查询的 RangeTblEntry,其中包含了子查询的元数据信息 RangeTblEntry* childRTE = root->simple_rte_array[childRTindex]; + + // 处理与子查询关联的安全性条款 process_security_barrier_quals(root, childRTE, qualscope, false); + + // 释放创建的 Relids 集合的内存,以避免内存泄漏 pfree(qualscope); } } + /* * make_outerjoininfo * Build a SpecialJoinInfo for the current outer join @@ -905,20 +910,30 @@ void process_security_clause_appendrel(PlannerInfo *root) static SpecialJoinInfo* make_outerjoininfo( PlannerInfo* root, Relids left_rels, Relids right_rels, Relids inner_join_rels, JoinType jointype, List* clause) { + // 创建 SpecialJoinInfo 结构体并分配内存 SpecialJoinInfo* sjinfo = makeNode(SpecialJoinInfo); + + // 用于存储在 JOIN 条件中出现的所有关系的集合 Relids clause_relids; + + // 用于存储在 JOIN 条件中出现的所有关系的集合,其中不包括 INNER JOIN 中的关系 Relids strict_relids; + + // 用于存储左侧关系的最小集合 Relids min_lefthand; + + // 用于存储右侧关系的最小集合 Relids min_righthand; + ListCell* l = NULL; /* - * We should not see RIGHT JOIN here because left/right were switched - * earlier + * 在这里,我们不应该看到 RIGHT JOIN,因为在之前已经交换了左/右关系。 + * 这个断言用于确保不会出现不支持的连接类型。 */ AssertEreport(jointype != JOIN_RIGHT && jointype != JOIN_INNER && jointype != JOIN_RIGHT_ANTI_FULL, MOD_OPT, - "unexpected join type."); + "意外的连接类型。"); /* * Presently the executor cannot support FOR [KEY] UPDATE/SHARE marking of rels @@ -936,35 +951,36 @@ static SpecialJoinInfo* make_outerjoininfo( * list everything. */ foreach (l, root->parse->rowMarks) { - RowMarkClause* rc = (RowMarkClause*)lfirst(l); + RowMarkClause* rc = (RowMarkClause*)lfirst(l); - if (bms_is_member(rc->rti, right_rels) || (jointype == JOIN_FULL && bms_is_member(rc->rti, left_rels))) { - ereport(ERROR, - (errmodule(MOD_OPT), - errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + // 检查是否存在不支持的情况,即在外连接的可空一侧应用SELECT FOR UPDATE/SHARE/NO KEY UPDATE/KEY SHARE + if (bms_is_member(rc->rti, right_rels) || (jointype == JOIN_FULL && bms_is_member(rc->rti, left_rels))) { + ereport(ERROR, + (errmodule(MOD_OPT), + errcode(ERRCODE_FEATURE_NOT_SUPPORTED), #ifndef ENABLE_MULTIPLE_NODES - errmsg("SELECT FOR UPDATE/SHARE/NO KEY UPDATE/KEY SHARE cannot be applied to the nullable side " - "of an outer join"))); + errmsg("SELECT FOR UPDATE/SHARE/NO KEY UPDATE/KEY SHARE 不能应用于外连接的可空一侧"))); #else - errmsg("SELECT FOR UPDATE/SHARE cannot be applied to the nullable side of an outer join"))); + errmsg("SELECT FOR UPDATE/SHARE 不能应用于外连接的可空一侧"))); #endif - } } +} - sjinfo->syn_lefthand = left_rels; - sjinfo->syn_righthand = right_rels; - sjinfo->jointype = jointype; - /* this always starts out false */ - sjinfo->delay_upper_joins = false; - sjinfo->join_quals = clause; +// 设置 SpecialJoinInfo 结构的各个字段 + sjinfo->syn_lefthand = left_rels; // 左侧关系的集合 + sjinfo->syn_righthand = right_rels; // 右侧关系的集合 + sjinfo->jointype = jointype; // 连接类型(INNER JOIN、LEFT JOIN、RIGHT JOIN 等) + sjinfo->delay_upper_joins = false; // 延迟处理上层连接的标志,初始设置为false + sjinfo->join_quals = clause; // 连接条件表达式的列表 + +// 如果是全连接(JOIN_FULL),不需要特别处理,直接设置各个字段并返回 + if (jointype == JOIN_FULL) { + sjinfo->min_lefthand = bms_copy(left_rels); // 复制左侧关系的集合 + sjinfo->min_righthand = bms_copy(right_rels); // 复制右侧关系的集合 + sjinfo->lhs_strict = false; // 不需要考虑此字段,设置为false + return sjinfo; +} - /* If it's a full join, no need to be very smart */ - if (jointype == JOIN_FULL) { - sjinfo->min_lefthand = bms_copy(left_rels); - sjinfo->min_righthand = bms_copy(right_rels); - sjinfo->lhs_strict = false; /* don't care about this */ - return sjinfo; - } /* * Retrieve all relids mentioned within the join clause. @@ -1163,14 +1179,15 @@ void distribute_qual_to_rels(PlannerInfo* root, Node* clause, bool is_deduced, b Index security_level, Relids qualscope, Relids ojscope, Relids outerjoin_nonnullable, Relids deduced_nullable_relids, List **postponed_qual_list) { - Relids relids; - bool is_pushed_down = false; - bool outerjoin_delayed = false; - bool pseudoconstant = false; - bool maybe_equivalence = false; - bool maybe_outer_join = false; - Relids nullable_relids; - RestrictInfo* restrictinfo = NULL; + Relids relids; // 用于存储与当前表达式相关的关系的集合 + bool is_pushed_down = false; // 用于表示表达式是否已被推到下层连接 + bool outerjoin_delayed = false; // 用于表示外连接是否已被延迟处理 + bool pseudoconstant = false; // 用于表示表达式是否是伪常量 + bool maybe_equivalence = false; // 用于表示表达式是否可能是等价表达式 + bool maybe_outer_join = false; // 用于表示表达式是否可能与外连接相关 + Relids nullable_relids; // 用于存储与表达式相关的可空关系的集合 + RestrictInfo* restrictinfo = NULL; // 用于存储约束信息的结构体,表示与表达式相关的约束条件 + /* * Retrieve all relids mentioned within the clause. @@ -1543,18 +1560,18 @@ static bool check_outerjoin_delay(PlannerInfo* root, Relids* relids_p, /* in/out Relids* nullable_relids_p, /* output parameter */ bool is_pushed_down) { - Relids relids; - Relids nullable_relids; - bool outerjoin_delayed = false; - bool found_some = false; + Relids relids; // 用于存储关系集合的副本 + Relids nullable_relids; // 用于存储可空关系集合 + bool outerjoin_delayed = false; // 用于表示外连接是否已被延迟处理 + bool found_some = false; // 用于标记是否找到相关的外连接 - /* fast path if no special joins */ + /* 快速路径:如果没有特殊的连接操作(special joins) */ if (root->join_info_list == NIL) { *nullable_relids_p = NULL; return false; } - /* must copy relids because we need the original value at the end */ + /* 需要复制 relids,因为我们需要在最后保留原始值 */ relids = bms_copy(*relids_p); nullable_relids = NULL; outerjoin_delayed = false; @@ -1565,39 +1582,40 @@ static bool check_outerjoin_delay(PlannerInfo* root, Relids* relids_p, /* in/out foreach (l, root->join_info_list) { SpecialJoinInfo* sjinfo = (SpecialJoinInfo*)lfirst(l); - /* do we reference any nullable rels of this OJ? */ + /* 我们是否引用了这个特殊连接的可空关系? */ if (bms_overlap(relids, sjinfo->min_righthand) || (sjinfo->jointype == JOIN_FULL && bms_overlap(relids, sjinfo->min_lefthand))) { - /* yes; have we included all its rels in relids? */ + /* 是的;我们是否已经包含了所有关系? */ if (!bms_is_subset(sjinfo->min_lefthand, relids) || !bms_is_subset(sjinfo->min_righthand, relids)) { - /* no, so add them in */ + /* 没有,因此添加它们 */ relids = bms_add_members(relids, sjinfo->min_lefthand); relids = bms_add_members(relids, sjinfo->min_righthand); outerjoin_delayed = true; - /* we'll need another iteration */ + /* 我们需要进行另一次迭代 */ found_some = true; } - /* track all the nullable rels of relevant OJs */ + /* 跟踪所有相关特殊连接的可空关系 */ nullable_relids = bms_add_members(nullable_relids, sjinfo->min_righthand); if (sjinfo->jointype == JOIN_FULL) nullable_relids = bms_add_members(nullable_relids, sjinfo->min_lefthand); - /* set delay_upper_joins if needed */ + /* 如果需要,设置 delay_upper_joins */ if (is_pushed_down && sjinfo->jointype != JOIN_FULL && bms_overlap(relids, sjinfo->min_lefthand)) sjinfo->delay_upper_joins = true; } } } while (found_some); - /* identify just the actually-referenced nullable rels */ + /* 仅标识实际引用的可空关系 */ nullable_relids = bms_int_members(nullable_relids, *relids_p); - /* replace *relids_p, and return nullable_relids */ + /* 替换 *relids_p,并返回 nullable_relids */ bms_free_ext(*relids_p); *relids_p = relids; *nullable_relids_p = nullable_relids; return outerjoin_delayed; } + /* * check_equivalence_delay * Detect whether a potential equivalence clause is rendered unsafe @@ -1613,20 +1631,20 @@ static bool check_outerjoin_delay(PlannerInfo* root, Relids* relids_p, /* in/out */ static bool check_equivalence_delay(PlannerInfo* root, RestrictInfo* restrictinfo) { - Relids relids; - Relids nullable_relids; + Relids relids; // 用于存储关系集合 + Relids nullable_relids; // 用于存储可空关系集合 - /* fast path if no special joins */ + /* 快速路径:如果没有特殊的连接操作(special joins),则返回 true */ if (root->join_info_list == NIL) return true; - /* must copy restrictinfo's relids to avoid changing it */ + /* 必须复制 restrictinfo 的 relids 以避免更改它 */ relids = bms_copy(restrictinfo->left_relids); - /* check left side does not need delay */ + /* 检查左侧是否需要延迟 */ if (check_outerjoin_delay(root, &relids, &nullable_relids, true)) return false; - /* and similarly for the right side */ + /* 类似地,检查右侧是否需要延迟 */ relids = bms_copy(restrictinfo->right_relids); if (check_outerjoin_delay(root, &relids, &nullable_relids, true)) return false; @@ -1634,6 +1652,7 @@ static bool check_equivalence_delay(PlannerInfo* root, RestrictInfo* restrictinf return true; } + /* * check_redundant_nullability_qual * Check to see if the qual is an IS NULL qual that is redundant with @@ -1646,30 +1665,30 @@ static bool check_equivalence_delay(PlannerInfo* root, RestrictInfo* restrictinf */ static bool check_redundant_nullability_qual(PlannerInfo* root, Node* clause) { - Var* forced_null_var = NULL; - Index forced_null_rel; + Var* forced_null_var = NULL; // 存储被强制为 NULL 的变量 + Index forced_null_rel; // 存储被强制为 NULL 的关系编号 ListCell* lc = NULL; - /* Check for IS NULL, and identify the Var forced to NULL */ + /* 检查是否为 IS NULL 条件,并确定被强制设置为 NULL 的变量 */ forced_null_var = find_forced_null_var(clause); if (forced_null_var == NULL) - return false; + return false; // 不是 IS NULL 条件,返回 false forced_null_rel = forced_null_var->varno; /* - * If the Var comes from the nullable side of a lower antijoin, the IS - * NULL condition is necessarily true. + * 如果变量来自于较低级别反连接(lower antijoin)的可空侧,IS NULL 条件肯定为真。 */ foreach (lc, root->join_info_list) { SpecialJoinInfo* sjinfo = (SpecialJoinInfo*)lfirst(lc); if (sjinfo->jointype == JOIN_ANTI && bms_is_member(forced_null_rel, sjinfo->syn_righthand)) - return true; + return true; // 变量位于反连接的可空侧,返回 true } - return false; + return false; // 变量不在反连接的可空侧,返回 false } + /* * distribute_restrictinfo_to_rels * Push a completed RestrictInfo into the proper restriction or join