diff options
Diffstat (limited to 'src/backend/optimizer/plan/analyzejoins.c')
-rw-r--r-- | src/backend/optimizer/plan/analyzejoins.c | 44 |
1 files changed, 17 insertions, 27 deletions
diff --git a/src/backend/optimizer/plan/analyzejoins.c b/src/backend/optimizer/plan/analyzejoins.c index dfb2e378312..7912b153c59 100644 --- a/src/backend/optimizer/plan/analyzejoins.c +++ b/src/backend/optimizer/plan/analyzejoins.c @@ -240,10 +240,10 @@ join_is_removable(PlannerInfo *root, SpecialJoinInfo *sjinfo) { PlaceHolderInfo *phinfo = (PlaceHolderInfo *) lfirst(l); - if (bms_is_subset(phinfo->ph_needed, joinrelids)) - continue; /* PHV is not used above the join */ if (bms_overlap(phinfo->ph_lateral, innerrel->relids)) return false; /* it references innerrel laterally */ + if (bms_is_subset(phinfo->ph_needed, joinrelids)) + continue; /* PHV is not used above the join */ if (!bms_overlap(phinfo->ph_eval_at, innerrel->relids)) continue; /* it definitely doesn't reference innerrel */ if (bms_is_subset(phinfo->ph_eval_at, innerrel->relids)) @@ -439,47 +439,37 @@ remove_rel_from_query(PlannerInfo *root, int relid, Relids joinrelids) sjinfo->syn_righthand = bms_del_member(sjinfo->syn_righthand, relid); } - /* - * Likewise remove references from LateralJoinInfo data structures. - * - * If we are deleting a LATERAL subquery, we can forget its - * LateralJoinInfos altogether. Otherwise, make sure the target is not - * 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) - { - LateralJoinInfo *ljinfo = (LateralJoinInfo *) lfirst(l); - - nextl = lnext(l); - ljinfo->lateral_rhs = bms_del_member(ljinfo->lateral_rhs, relid); - if (bms_is_empty(ljinfo->lateral_rhs)) - root->lateral_info_list = list_delete_ptr(root->lateral_info_list, - ljinfo); - else - { - ljinfo->lateral_lhs = bms_del_member(ljinfo->lateral_lhs, relid); - Assert(!bms_is_empty(ljinfo->lateral_lhs)); - } - } + /* There shouldn't be any LATERAL info to translate, as yet */ + Assert(root->lateral_info_list == NIL); /* * Likewise remove references from PlaceHolderVar data structures, * removing any no-longer-needed placeholders entirely. + * + * Removal is a bit tricker than it might seem: we can remove PHVs that + * are used at the target rel and/or in the join qual, but not those that + * are used at join partner rels or above the join. It's not that easy to + * distinguish PHVs used at partner rels from those used in the join qual, + * since they will both have ph_needed sets that are subsets of + * joinrelids. However, a PHV used at a partner rel could not have the + * target rel in ph_eval_at, so we check that while deciding whether to + * remove or just update the PHV. There is no corresponding test in + * join_is_removable because it doesn't need to distinguish those cases. */ for (l = list_head(root->placeholder_list); l != NULL; l = nextl) { PlaceHolderInfo *phinfo = (PlaceHolderInfo *) lfirst(l); nextl = lnext(l); - if (bms_is_subset(phinfo->ph_needed, joinrelids)) + Assert(!bms_is_member(relid, phinfo->ph_lateral)); + if (bms_is_subset(phinfo->ph_needed, joinrelids) && + bms_is_member(relid, phinfo->ph_eval_at)) root->placeholder_list = list_delete_ptr(root->placeholder_list, phinfo); else { phinfo->ph_eval_at = bms_del_member(phinfo->ph_eval_at, relid); Assert(!bms_is_empty(phinfo->ph_eval_at)); - Assert(!bms_is_member(relid, phinfo->ph_lateral)); phinfo->ph_needed = bms_del_member(phinfo->ph_needed, relid); } } |