enter
This commit is contained in:
parent
ab615844e1
commit
4a70a794cd
|
|
@ -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 不应为空<E4B8BA><E7A9BA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>它表示需要这些变量的关系的集合。
|
||||
// 断言 where_needed 不应为空<E4B8BA><E7A9BA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>它表示需要这些变量的关系的集合。
|
||||
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; // 标识哪些关系需要哪些<EFBFBD><EFBFBD><EFBFBD>量
|
||||
Relids where_needed = NULL; // 标识哪些关系需要<EFBFBD><EFBFBD><EFBFBD>些<EFBFBD><EFBFBD><EFBFBD>量
|
||||
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
|
||||
|
|
|
|||
Loading…
Reference in New Issue