This commit is contained in:
Cachuela 2023-09-25 20:17:42 +08:00
parent c4a23cca76
commit 332fbf113f
1 changed files with 114 additions and 86 deletions

View File

@ -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;// 如果未找到,返回无效的操作符标识
}