diff --git a/src/gausskernel/optimizer/plan/analyzejoins.cpp b/src/gausskernel/optimizer/plan/analyzejoins.cpp index abb6912ee..346e5680f 100644 --- a/src/gausskernel/optimizer/plan/analyzejoins.cpp +++ b/src/gausskernel/optimizer/plan/analyzejoins.cpp @@ -34,12 +34,19 @@ #include "utils/lsyscache.h" /* local functions */ +// 检查特殊连接是否可移除 static bool join_is_removable(PlannerInfo* root, SpecialJoinInfo* sjinfo); +// 从查询中移除关系 static void remove_rel_from_query(PlannerInfo* root, int relid, Relids joinrelids); +// 从连接列表中移除关系 static List* remove_rel_from_joinlist(List* joinlist, int relid, int* nremoved); +// 检查关系是否支持去重 static bool rel_supports_distinctness(PlannerInfo* root, RelOptInfo* rel); +// 检查关系是否对指定子句去重 static bool rel_is_distinct_for(PlannerInfo* root, RelOptInfo* rel, List* clause_list); +// 检查列的唯一性 static bool check_column_uniqueness(List* groupClause, List* targetList, List* colnos, List* opids); +// 查找具有唯一性的列 static Oid distinct_col_search(int colno, List* colnos, List* opids); /* @@ -50,23 +57,25 @@ static Oid distinct_col_search(int colno, List* colnos, List* opids); * We are passed the current joinlist and return the updated list. Other * data structures that have to be updated are accessible via "root". */ -List* remove_useless_joins(PlannerInfo* root, List* joinlist) +List* remove_useless_joins(PlannerInfo* root, List* joinlist)// 移除无用的连接 { - ListCell* lc = NULL; - ListCell* pnext = NULL; + ListCell* lc = NULL;// 用于遍历join_info_list的指针 + ListCell* pnext = NULL;// 用于保存下一个元素的指针 /* * We are only interested in relations that are left-joined to, so we can * scan the join_info_list to find them easily. */ restart: +// 遍历特殊连接信息列表 join_info_list for (lc = list_head(root->join_info_list); lc != NULL; lc = pnext) { - SpecialJoinInfo* sjinfo = (SpecialJoinInfo*)lfirst(lc); - pnext = lnext(lc); - int innerrelid; - int nremoved; + SpecialJoinInfo* sjinfo = (SpecialJoinInfo*)lfirst(lc);// 获取特殊连接信息 + pnext = lnext(lc); // 保存下一个元素的指针 + int innerrelid;// 内部关系的标识符 + int nremoved;// 移除的关系数量 /* Skip if not removable */ + // 检查特殊连接是否可移除,如果不可移除则继续下一个连接 if (!join_is_removable(root, sjinfo)) continue; @@ -75,14 +84,14 @@ restart: * righthand is a single baserel. Remove that rel from the query and * joinlist. */ - innerrelid = bms_singleton_member(sjinfo->min_righthand); + innerrelid = bms_singleton_member(sjinfo->min_righthand);// 获取内部关系的标识符 - remove_rel_from_query(root, innerrelid, bms_union(sjinfo->min_lefthand, sjinfo->min_righthand)); + remove_rel_from_query(root, innerrelid, bms_union(sjinfo->min_lefthand, sjinfo->min_righthand));// 从查询中移除内部关系 /* We verify that exactly one reference gets removed from joinlist */ nremoved = 0; - joinlist = remove_rel_from_joinlist(joinlist, innerrelid, &nremoved); - if (nremoved != 1) + joinlist = remove_rel_from_joinlist(joinlist, innerrelid, &nremoved);// 从连接列表 joinlist 中移除内部关系,并记录移除的关系数量 + if (nremoved != 1)// 从连接列表 joinlist 中移除内部关系,并记录移除的关系数量 ereport(ERROR, (errmodule(MOD_OPT), errcode(ERRCODE_OPTIMIZER_INCONSISTENT_STATE), @@ -92,7 +101,7 @@ restart: * We can delete this SpecialJoinInfo from the list too, since it's no * longer of interest. */ - root->join_info_list = list_delete_ptr(root->join_info_list, sjinfo); + root->join_info_list = list_delete_ptr(root->join_info_list, sjinfo);// 从连接列表 joinlist 中移除内部关系,并记录移除的关系数量 /* * Restart the scan. This is necessary to ensure we find all @@ -102,10 +111,10 @@ restart: * current list cell, we'd have to have some kluge to continue the * list scan anyway. */ - goto restart; + goto restart;// 从连接列表 joinlist 中移除内部关系,并记录移除的关系数量 } - return joinlist; + return joinlist;// 从连接列表 joinlist 中移除内部关系,并记录移除的关系数量 } /* @@ -118,18 +127,21 @@ restart: * rather than mixing outer and inner vars on either side. If it matches, * we set the transient flag outer_is_left to identify which side is which. */ -static inline bool clause_sides_match_join(RestrictInfo* rinfo, Relids outerrelids, Relids innerrelids) +static inline bool clause_sides_match_join(RestrictInfo* rinfo, Relids outerrelids, Relids innerrelids)// 内联函数,检查子句的两侧是否匹配连接 + { + // 检查约束信息的左侧关系是否是外部关系的子集,右侧关系是否是内部关系的子集 if (bms_is_subset(rinfo->left_relids, outerrelids) && bms_is_subset(rinfo->right_relids, innerrelids)) { /* lefthand side is outer */ - rinfo->outer_is_left = true; - return true; + rinfo->outer_is_left = true;// 设置 outer_is_left 为 true,表示左侧关系在连接中是外部关系 + return true;// 返回 true,表示约束信息的关系符合连接 } else if (bms_is_subset(rinfo->left_relids, innerrelids) && bms_is_subset(rinfo->right_relids, outerrelids)) { /* righthand side is outer */ - rinfo->outer_is_left = false; - return true; + rinfo->outer_is_left = false;// 设置 outer_is_left 为 false,表示左侧关系在连接中是内部关系 + return true;// 返回 true,表示约束信息的关系符合连接 } return false; /* no good for these input relations */ + // 如果左右关系都不符合连接,返回 false } /* @@ -143,7 +155,7 @@ static inline bool clause_sides_match_join(RestrictInfo* rinfo, Relids outerreli * have to check that the inner side doesn't generate any variables needed * above the join. */ -static bool join_is_removable(PlannerInfo* root, SpecialJoinInfo* sjinfo) +static bool join_is_removable(PlannerInfo* root, SpecialJoinInfo* sjinfo)// 检查连接是否可移除 { int innerrelid; RelOptInfo* innerrel = NULL; @@ -156,6 +168,7 @@ static bool join_is_removable(PlannerInfo* root, SpecialJoinInfo* sjinfo) * Must be a non-delaying left join to a single baserel, else we aren't * going to be able to do anything with it. */ + // 仅适用于左连接和左反连接,且右侧关系为单一关系 if ((sjinfo->jointype != JOIN_LEFT && sjinfo->jointype != JOIN_LEFT_ANTI_FULL) || sjinfo->delay_upper_joins || bms_membership(sjinfo->min_righthand) != BMS_SINGLETON) return false; @@ -168,11 +181,11 @@ static bool join_is_removable(PlannerInfo* root, SpecialJoinInfo* sjinfo) * are needed above the join, make a quick check to eliminate cases in * which we will surely be unable to prove uniqueness of the innerrel. */ - if (!rel_supports_distinctness(root, innerrel)) + if (!rel_supports_distinctness(root, innerrel))// 检查右侧关系是否支持去重 return false; /* Compute the relid set for the join we are considering */ - joinrelids = bms_union(sjinfo->min_lefthand, sjinfo->min_righthand); + joinrelids = bms_union(sjinfo->min_lefthand, sjinfo->min_righthand);// 计算连接关系的集合 /* * We can't remove the join if any inner-rel attributes are used above the @@ -187,7 +200,7 @@ static bool join_is_removable(PlannerInfo* root, SpecialJoinInfo* sjinfo) * theory that the system attributes are somewhat less likely to be wanted * and should be tested last. */ - for (attroff = innerrel->max_attr - innerrel->min_attr; attroff >= 0; attroff--) { + for (attroff = innerrel->max_attr - innerrel->min_attr; attroff >= 0; attroff--) {// 检查左侧关系所需的属性是否完全包含在右侧关系中 if (!bms_is_subset(innerrel->attr_needed[attroff], joinrelids)) return false; } @@ -199,7 +212,7 @@ static bool join_is_removable(PlannerInfo* root, SpecialJoinInfo* sjinfo) * for that is relatively expensive, so we first check against ph_eval_at, * which must mention the inner rel if the PHV uses any inner-rel attrs. */ - foreach (l, root->placeholder_list) { + foreach (l, root->placeholder_list) {// 检查占位符的需要属性是否完全包含在右侧关系中 PlaceHolderInfo* phinfo = (PlaceHolderInfo*)lfirst(l); if (bms_is_subset(phinfo->ph_needed, joinrelids)) @@ -217,7 +230,7 @@ static bool join_is_removable(PlannerInfo* root, SpecialJoinInfo* sjinfo) * it's what we want. The mergejoinability test also eliminates clauses * containing volatile functions, which we couldn't depend on. */ - foreach (l, innerrel->joininfo) { + foreach (l, innerrel->joininfo) {// 遍历右侧关系的连接信息,检查是否符合移除条件 RestrictInfo* restrictinfo = (RestrictInfo*)lfirst(l); /* @@ -226,6 +239,7 @@ static bool join_is_removable(PlannerInfo* root, SpecialJoinInfo* sjinfo) * above the outer join, even if it references no other rels (it might * be from WHERE, for example). */ + // 如果约束已下推或所需关系不符合连接关系,则跳过 if (restrictinfo->is_pushed_down || !bms_equal(restrictinfo->required_relids, joinrelids)) { /* * If such a clause actually references the inner rel then join @@ -246,11 +260,11 @@ static bool join_is_removable(PlannerInfo* root, SpecialJoinInfo* sjinfo) * Check if clause has the form "outer op inner" or "inner op outer", * and if so mark which side is inner. */ - if (!clause_sides_match_join(restrictinfo, sjinfo->min_lefthand, innerrel->relids)) + if (!clause_sides_match_join(restrictinfo, sjinfo->min_lefthand, innerrel->relids))// 检查约束的两侧是否匹配连接 continue; /* no good for these input relations */ /* OK, add to list */ - clause_list = lappend(clause_list, restrictinfo); + clause_list = lappend(clause_list, restrictinfo); // 将符合条件的约束加入列表 } /* @@ -277,38 +291,42 @@ static bool join_is_removable(PlannerInfo* root, SpecialJoinInfo* sjinfo) * Also, join quals involving the rel have to be removed from the joininfo * lists, but only if they belong to the outer join identified by joinrelids. */ + // 静态函数,用于从查询计划中移除与给定 relid 关联的关系 static void remove_rel_from_query(PlannerInfo* root, int relid, Relids joinrelids) { - RelOptInfo* rel = find_base_rel(root, relid); - List* joininfos = NIL; - Index rti; - ListCell* l = NULL; + RelOptInfo* rel = find_base_rel(root, relid);// 查找与给定 relid 相关的 RelOptInfo 结构体 + List* joininfos = NIL;// 用于存储连接信息的列表 + Index rti;// 用于遍历 RelOptInfo 结构体数组的索引 + ListCell* l = NULL;// 用于循环迭代的列表元素指针 ListCell* nextl = NULL; /* * Mark the rel as "dead" to show it is no longer part of the join tree. * (Removing it from the baserel array altogether seems too risky.) */ - rel->reloptkind = RELOPT_DEADREL; + rel->reloptkind = RELOPT_DEADREL;// 将 rel 标记为已删除状态 /* * Remove references to the rel from other baserels' attr_needed arrays. */ - for (rti = 1; rti < (unsigned int)root->simple_rel_array_size; rti++) { - RelOptInfo* otherrel = root->simple_rel_array[rti]; + for (rti = 1; rti < (unsigned int)root->simple_rel_array_size; rti++) {// 遍历 simple_rel_array 数组中的 RelOptInfo 结构体 + RelOptInfo* otherrel = root->simple_rel_array[rti]; // 获取当前的 RelOptInfo 结构体 int attroff; /* there may be empty slots corresponding to non-baserel RTEs */ + + // 如果 RelOptInfo 结构体为空,则继续下一轮循环 if (otherrel == NULL) continue; + // 断言确保 RelOptInfo 的索引正确 AssertEreport(otherrel->relid == rti, MOD_OPT, "RelOptInfo Index Incorrect."); /* no point in processing target rel itself */ - if (otherrel == rel) + if (otherrel == rel)// 如果当前的 RelOptInfo 与目标 rel 相同,则继续下一轮循环 continue; - for (attroff = otherrel->max_attr - otherrel->min_attr; attroff >= 0; attroff--) { + for (attroff = otherrel->max_attr - otherrel->min_attr; attroff >= 0; attroff--) {// 遍历属性列表,从属性的 attr_needed 中删除 relid otherrel->attr_needed[attroff] = bms_del_member(otherrel->attr_needed[attroff], relid); } } @@ -321,7 +339,7 @@ static void remove_rel_from_query(PlannerInfo* root, int relid, Relids joinrelid * RHS of the target outer join will be made empty here, but that's OK * since caller will delete that SpecialJoinInfo entirely. */ - foreach (l, root->join_info_list) { + foreach (l, root->join_info_list) {// 遍历 join_info_list 列表,更新连接信息中的左右关系 SpecialJoinInfo* sjinfo = (SpecialJoinInfo*)lfirst(l); sjinfo->min_lefthand = bms_del_member(sjinfo->min_lefthand, relid); @@ -338,11 +356,12 @@ static void remove_rel_from_query(PlannerInfo* root, int relid, Relids joinrelid * included in any lateral_lhs set. (It probably can't be, since that * should have precluded deciding to remove it; but let's cope anyway.) */ - for (l = list_head(root->lateral_info_list); l != NULL; l = nextl) + for (l = list_head(root->lateral_info_list); l != NULL; l = nextl)// 遍历 lateral_info_list 列表,更新 lateral 关系信息 { LateralJoinInfo *ljinfo = (LateralJoinInfo *) lfirst(l); nextl = lnext(l); + // 如果 lateral_rhs 与给定的 relid 相同,则从列表中删除该项 if (ljinfo->lateral_rhs == (Index)relid) root->lateral_info_list = list_delete_ptr(root->lateral_info_list, ljinfo); @@ -358,14 +377,14 @@ static void remove_rel_from_query(PlannerInfo* root, int relid, Relids joinrelid * set. An empty eval_at set would confuse later processing since it * would match every possible eval placement. */ - foreach (l, root->placeholder_list) { + foreach (l, root->placeholder_list) {// 遍历 placeholder_list 列表,更新占位符信息 PlaceHolderInfo* phinfo = (PlaceHolderInfo*)lfirst(l); - phinfo->ph_eval_at = bms_del_member(phinfo->ph_eval_at, relid); - if (bms_is_empty(phinfo->ph_eval_at)) /* oops, belay that */ + phinfo->ph_eval_at = bms_del_member(phinfo->ph_eval_at, relid);// 从 ph_eval_at 中删除 relid + if (bms_is_empty(phinfo->ph_eval_at)) /* oops, belay that */// 如果 ph_eval_at 变为空集,将 relid 添加回去 phinfo->ph_eval_at = bms_add_member(phinfo->ph_eval_at, relid); - phinfo->ph_needed = bms_del_member(phinfo->ph_needed, relid); + phinfo->ph_needed = bms_del_member(phinfo->ph_needed, relid);// 从 ph_needed 中删除 relid } /* @@ -382,22 +401,22 @@ static void remove_rel_from_query(PlannerInfo* root, int relid, Relids joinrelid * loop, because otherwise remove_join_clause_from_rels would destroy the * list while we're scanning it. */ - joininfos = list_copy(rel->joininfo); + joininfos = list_copy(rel->joininfo);// 复制 rel 的 joininfo 列表,并遍历处理 foreach (l, joininfos) { RestrictInfo* rinfo = (RestrictInfo*)lfirst(l); - remove_join_clause_from_rels(root, rinfo, rinfo->required_relids); + remove_join_clause_from_rels(root, rinfo, rinfo->required_relids);// 从连接信息中移除与 relid 相关的子句 - if (rinfo->is_pushed_down || !bms_equal(rinfo->required_relids, joinrelids)) { + if (rinfo->is_pushed_down || !bms_equal(rinfo->required_relids, joinrelids)) {// 如果子句已被推送下来或者不等于 joinrelids,则进行处理 /* Recheck that qual doesn't actually reference the target rel */ AssertEreport(!bms_is_member(relid, rinfo->clause_relids), MOD_OPT, ""); /* * The required_relids probably aren't shared with anything else, * but let's copy them just to be sure. */ - rinfo->required_relids = bms_copy(rinfo->required_relids); + rinfo->required_relids = bms_copy(rinfo->required_relids);// 复制 required_relids,然后从中删除 relid rinfo->required_relids = bms_del_member(rinfo->required_relids, relid); - distribute_restrictinfo_to_rels(root, rinfo); + distribute_restrictinfo_to_rels(root, rinfo);// 将处理后的信息重新分发到相关的 RelOptInfo 结构体中 } } } @@ -411,22 +430,23 @@ static void remove_rel_from_query(PlannerInfo* root, int relid, Relids joinrelid * *nremoved is incremented by the number of occurrences removed (there * should be exactly one, but the caller checks that). */ + // 静态函数,从连接列表中移除与给定 relid 相关的关系 static List* remove_rel_from_joinlist(List* joinlist, int relid, int* nremoved) { - List* result = NIL; - ListCell* jl = NULL; + List* result = NIL;// 用于存储结果的列表 + ListCell* jl = NULL;// 用于遍历连接列表的列表元素指针 - foreach (jl, joinlist) { - Node* jlnode = (Node*)lfirst(jl); + foreach (jl, joinlist) {// 遍历连接列表 + Node* jlnode = (Node*)lfirst(jl);// 获取当前列表元素 - if (IsA(jlnode, RangeTblRef)) { + if (IsA(jlnode, RangeTblRef)) {// 如果当前元素是 RangeTblRef int varno = ((RangeTblRef*)jlnode)->rtindex; - if (varno == relid) + if (varno == relid)// 如果 varno 等于 relid,则增加 nremoved 计数 (*nremoved)++; - else + else// 否则将当前元素添加到结果列表中 result = lappend(result, jlnode); - } else if (IsA(jlnode, List)) { + } else if (IsA(jlnode, List)) {// 如果当前元素是 List,则递归调用 remove_rel_from_joinlist 处理子列表 /* Recurse to handle subproblem */ List* sublist = NIL; @@ -434,7 +454,7 @@ static List* remove_rel_from_joinlist(List* joinlist, int relid, int* nremoved) /* Avoid including empty sub-lists in the result */ if (sublist != NIL) result = lappend(result, sublist); - } else { + } else {// 如果是其他类型的节点,则报错 ereport(ERROR, (errmodule(MOD_OPT), errcode(ERRCODE_UNEXPECTED_NODE_STATE), @@ -443,7 +463,7 @@ static List* remove_rel_from_joinlist(List* joinlist, int relid, int* nremoved) } } - return result; + return result;// 返回处理后的结果列表 } /* @@ -457,7 +477,7 @@ static List* remove_rel_from_joinlist(List* joinlist, int relid, int* nremoved) * rel_is_distinct_for()'s argument lists if the call could not possibly * succeed. */ -static bool rel_supports_distinctness(PlannerInfo* root, RelOptInfo* rel) +static bool rel_supports_distinctness(PlannerInfo* root, RelOptInfo* rel)// 静态函数,判断 rel 是否支持 DISTINCT 操作 { /* * We only handle two cases here: @@ -465,9 +485,9 @@ static bool rel_supports_distinctness(PlannerInfo* root, RelOptInfo* rel) * 2. subquery with aggreations * We can improve later when we can propagate uniqueness */ - if (rel->reloptkind != RELOPT_BASEREL) + if (rel->reloptkind != RELOPT_BASEREL)// 如果 rel 不是基本关系,则不支持 DISTINCT return false; - if (rel->rtekind == RTE_RELATION) { + if (rel->rtekind == RTE_RELATION) {// 如果 rel 是关系表(RTE_RELATION) /* * For a plain relation, we only know how to prove uniqueness by * reference to unique indexes. Make sure there's at least one @@ -475,17 +495,18 @@ static bool rel_supports_distinctness(PlannerInfo* root, RelOptInfo* rel) * it's a partial index, it must match the query. (Keep these * conditions in sync with relation_has_unique_index_for!) */ + // 遍历索引列表,查找唯一且立即可用的索引 ListCell* lc = NULL; foreach (lc, rel->indexlist) { IndexOptInfo* ind = (IndexOptInfo*)lfirst(lc); - + // 如果索引是唯一的、立即可用的,并且没有过滤条件,则支持 DISTINCT if (ind->unique && ind->immediate && (ind->indpred == NIL || ind->predOK)) return true; } } else if (rel->rtekind == RTE_SUBQUERY) { Query* subquery = root->simple_rte_array[rel->relid]->subquery; - + // 如果 rel 是子查询,则判断子查询是否支持 DISTINCT /* Check if the subquery has any qualities that support distinctness */ if (query_supports_distinctness(subquery)) return true; @@ -512,24 +533,25 @@ static bool rel_supports_distinctness(PlannerInfo* root, RelOptInfo* rel) * is OK for current uses, because the clause_list is built by the caller for * the sole purpose of passing to this function. */ -static bool rel_is_distinct_for(PlannerInfo* root, RelOptInfo* rel, List* clause_list) +static bool rel_is_distinct_for(PlannerInfo* root, RelOptInfo* rel, List* clause_list)// 静态函数,判断 rel 是否对给定的列列表支持 DISTINCT 操作 { /* * We could skip a couple of tests here if we assume all callers checked * rel_supports_distinctness first, but it doesn't seem worth taking any * risk for. */ - if (rel->reloptkind != RELOPT_BASEREL) + if (rel->reloptkind != RELOPT_BASEREL)// 如果 rel 不是基本关系,则不支持 DISTINCT return false; - if (rel->rtekind == RTE_RELATION) { + if (rel->rtekind == RTE_RELATION) {// 如果 rel 是关系表(RTE_RELATION) + /* * Examine the indexes to see if we have a matching unique index. * relation_has_unique_index_for automatically adds any usable * restriction clauses for the rel, so we needn't do that here. */ - if (relation_has_unique_index_for(root, rel, clause_list, NIL, NIL)) + if (relation_has_unique_index_for(root, rel, clause_list, NIL, NIL))// 调用 relation_has_unique_index_for 函数判断是否有唯一索引支持 DISTINCT return true; - } else if (rel->rtekind == RTE_SUBQUERY) { + } else if (rel->rtekind == RTE_SUBQUERY) {// 如果 rel 是子查询,则判断子查询是否支持 DISTINCT Index relid = rel->relid; Query* subquery = root->simple_rte_array[relid]->subquery; List* colnos = NIL; @@ -545,7 +567,7 @@ static bool rel_is_distinct_for(PlannerInfo* root, RelOptInfo* rel, List* clause * (XXX we are not considering restriction clauses attached to the * subquery; is that worth doing?) */ - foreach (l, clause_list) { + foreach (l, clause_list) { // 遍历子句列表,获取列号和操作符号 RestrictInfo* rinfo = (RestrictInfo*)lfirst(l); Oid op; Var* var = NULL; @@ -567,7 +589,7 @@ static bool rel_is_distinct_for(PlannerInfo* root, RelOptInfo* rel, List* clause else var = (Var*)get_leftop(rinfo->clause); - if (var != NULL) { + if (var != NULL) { // 尝试找到兼容的 Var /* try to find compatible var */ var = locate_distribute_var((Expr*)var); } @@ -584,7 +606,7 @@ static bool rel_is_distinct_for(PlannerInfo* root, RelOptInfo* rel, List* clause opids = lappend_oid(opids, op); } - if (query_is_distinct_for(subquery, colnos, opids)) + if (query_is_distinct_for(subquery, colnos, opids))// 调用 query_is_distinct_for 函数判断子查询是否支持 DISTINCT return true; } return false; @@ -601,7 +623,7 @@ static bool rel_is_distinct_for(PlannerInfo* root, RelOptInfo* rel, List* clause * query_is_distinct_for()'s argument lists if the call could not possibly * succeed. */ -bool query_supports_distinctness(Query* query) +bool query_supports_distinctness(Query* query)// 判断查询是否支持 DISTINCT 操作 { if (query->distinctClause != NIL || query->groupClause != NIL || query->hasAggs || query->havingQual || query->setOperations) @@ -628,11 +650,12 @@ bool query_supports_distinctness(Query* query) * should give trustworthy answers for all operators that we might need * to deal with here.) */ -bool query_is_distinct_for(Query* query, List* colnos, List* opids) +bool query_is_distinct_for(Query* query, List* colnos, List* opids)// 判断查询是否对给定列列表 colnos 和操作符列表 opids 支持 DISTINCT 操作 { ListCell* l = NULL; Oid opid; + // 断言:列列表和操作符列表长度必须相等 Assert(list_length(colnos) == list_length(opids)); /* @@ -643,7 +666,7 @@ bool query_is_distinct_for(Query* query, List* colnos, List* opids) * specified columns, since those must be evaluated before de-duplication; * but it doesn't presently seem worth the complication to check that.) */ - if (expression_returns_set((Node*)query->targetList)) + if (expression_returns_set((Node*)query->targetList))// 如果查询的目标列表返回集合,则不支持 DISTINCT return false; /* @@ -651,8 +674,9 @@ bool query_is_distinct_for(Query* query, List* colnos, List* opids) * columns in the DISTINCT clause appear in colnos and operator semantics * match. */ + // 如果查询中存在 DISTINCT 子句 if (query->distinctClause != NIL) { - if (check_column_uniqueness(query->distinctClause, query->targetList, colnos, opids)) + if (check_column_uniqueness(query->distinctClause, query->targetList, colnos, opids))// 调用 check_column_uniqueness 函数检查列是否唯一 return true; } @@ -660,15 +684,15 @@ bool query_is_distinct_for(Query* query, List* colnos, List* opids) * Similarly, GROUP BY guarantees uniqueness if all the grouped columns * appear in colnos and operator semantics match. */ - if (query->groupClause != NIL && query->groupingSets == NIL) { - if (check_column_uniqueness(query->groupClause, query->targetList, colnos, opids)) + if (query->groupClause != NIL && query->groupingSets == NIL) {// 如果查询中存在 GROUP BY 子句且没有 GROUPING SETS + if (check_column_uniqueness(query->groupClause, query->targetList, colnos, opids))// 调用 check_column_uniqueness 函数检查列是否唯一 return true; } else if (query->groupingSets != NIL) { /* * If we have grouping sets with expressions, we probably don't have * uniqueness and analysis would be hard. Punt. */ - if (query->groupClause != NIL) + if (query->groupClause != NIL) // 如果存在 GROUPING SETS return false; /* @@ -677,13 +701,13 @@ bool query_is_distinct_for(Query* query, List* colnos, List* opids) * then we're returning only one row and are certainly unique. But * otherwise, we know we're certainly not unique. */ - bool isTrue = list_length(query->groupingSets) == 1 && + bool isTrue = list_length(query->groupingSets) == 1 &&// 如果 GROUPING SETS 只包含一个空集合 ((GroupingSet*)linitial(query->groupingSets))->kind == GROUPING_SET_EMPTY; if (isTrue) return true; else return false; - } else { + } else {// 如果查询中存在聚合函数或 HAVING 子句,则支持 DISTINCT /* * If we have no GROUP BY, but do have aggregates or HAVING, then the * result is at most one row so it's surely unique, for any operators. @@ -696,18 +720,19 @@ bool query_is_distinct_for(Query* query, List* colnos, List* opids) * UNION, INTERSECT, EXCEPT guarantee uniqueness of the whole output row, * except with ALL. */ + // 如果查询中存在集合操作 if (query->setOperations != NULL) { SetOperationStmt* topop = (SetOperationStmt*)query->setOperations; Assert(IsA(topop, SetOperationStmt)); Assert(topop->op != SETOP_NONE); - if (!topop->all) { + if (!topop->all) {// 如果不是 UNION ALL 操作 ListCell* lg = NULL; /* We're good if all the nonjunk output columns are in colnos */ lg = list_head(topop->groupClauses); - foreach (l, query->targetList) { + foreach (l, query->targetList) {// 遍历查询的目标列表 TargetEntry* tle = (TargetEntry*)lfirst(l); SortGroupClause* sgc = NULL; @@ -718,12 +743,13 @@ bool query_is_distinct_for(Query* query, List* colnos, List* opids) Assert(lg != NULL); sgc = (SortGroupClause*)lfirst(lg); lg = lnext(lg); - + // 调用 distinct_col_search 函数查找列的操作符 opid = distinct_col_search(tle->resno, colnos, opids); if (!OidIsValid(opid) || !equality_ops_are_compatible(opid, sgc->eqop)) break; /* exit early if no match */ } if (l == NULL) /* had matches for all? */ + // 如果成功遍历了所有目标列,说明支持 DISTINCT return true; } } @@ -744,7 +770,7 @@ bool query_is_distinct_for(Query* query, List* colnos, List* opids) * Given group clause and targetlist, find if all the aggregated columns * in colnos, return true if so, else false. */ -static bool check_column_uniqueness(List* groupClause, List* targetList, List* colnos, List* opids) +static bool check_column_uniqueness(List* groupClause, List* targetList, List* colnos, List* opids)// 检查列是否唯一 { ListCell* l = NULL; Oid opid; @@ -754,9 +780,11 @@ static bool check_column_uniqueness(List* groupClause, List* targetList, List* c TargetEntry* tle = get_sortgroupclause_tle(sgc, targetList); opid = distinct_col_search(tle->resno, colnos, opids); + // 如果操作符无效或不兼容,则中断循环 if (!OidIsValid(opid) || !equality_ops_are_compatible(opid, sgc->eqop)) break; /* exit early if no match */ } + // 如果成功遍历了所有列,说明支持 DISTINCT if (l == NULL) /* had matches for all? */ return true; @@ -770,15 +798,15 @@ static bool check_column_uniqueness(List* groupClause, List* targetList, List* c * else return InvalidOid. (Ordinarily colnos would not contain duplicates, * but if it does, we arbitrarily select the first match.) */ -static Oid distinct_col_search(int colno, List* colnos, List* opids) +static Oid distinct_col_search(int colno, List* colnos, List* opids)// 在列列表 colnos 中查找列的操作符 { ListCell* lc1 = NULL; ListCell* lc2 = NULL; - forboth(lc1, colnos, lc2, opids) + forboth(lc1, colnos, lc2, opids) // 同时遍历列列表和操作符列表 { if (colno == lfirst_int(lc1)) return lfirst_oid(lc2); } - return InvalidOid; + return InvalidOid;// 如果未找到,返回无效的操作符标识 }