3535
3636/* local functions */
3737static bool join_is_removable (PlannerInfo * root ,SpecialJoinInfo * sjinfo );
38- static void remove_rel_from_query (PlannerInfo * root ,int relid ,int ojrelid ,
39- Relids joinrelids );
38+ static void remove_rel_from_query (PlannerInfo * root ,int relid ,
39+ SpecialJoinInfo * sjinfo );
4040static void remove_rel_from_restrictinfo (RestrictInfo * rinfo ,
4141int relid ,int ojrelid );
4242static List * remove_rel_from_joinlist (List * joinlist ,int relid ,int * nremoved );
@@ -73,7 +73,6 @@ remove_useless_joins(PlannerInfo *root, List *joinlist)
7373foreach (lc ,root -> join_info_list )
7474{
7575SpecialJoinInfo * sjinfo = (SpecialJoinInfo * )lfirst (lc );
76- Relids joinrelids ;
7776int innerrelid ;
7877int nremoved ;
7978
@@ -88,12 +87,7 @@ remove_useless_joins(PlannerInfo *root, List *joinlist)
8887 */
8988innerrelid = bms_singleton_member (sjinfo -> min_righthand );
9089
91- /* Compute the relid set for the join we are considering */
92- joinrelids = bms_union (sjinfo -> min_lefthand ,sjinfo -> min_righthand );
93- if (sjinfo -> ojrelid != 0 )
94- joinrelids = bms_add_member (joinrelids ,sjinfo -> ojrelid );
95-
96- remove_rel_from_query (root ,innerrelid ,sjinfo -> ojrelid ,joinrelids );
90+ remove_rel_from_query (root ,innerrelid ,sjinfo );
9791
9892/* We verify that exactly one reference gets removed from joinlist */
9993nremoved = 0 ;
@@ -324,21 +318,29 @@ join_is_removable(PlannerInfo *root, SpecialJoinInfo *sjinfo)
324318
325319
326320/*
327- * Remove the target relid from the planner's data structures, having
328- * determined that there is no need to include it in the query.
321+ * Remove the target relid and references to the target join from the
322+ * planner's data structures, having determined that there is no need
323+ * to include them in the query.
329324 *
330325 * We are not terribly thorough here. We only bother to update parts of
331326 * the planner's data structures that will actually be consulted later.
332327 */
333328static void
334- remove_rel_from_query (PlannerInfo * root ,int relid ,int ojrelid ,
335- Relids joinrelids )
329+ remove_rel_from_query (PlannerInfo * root ,int relid ,SpecialJoinInfo * sjinfo )
336330{
337331RelOptInfo * rel = find_base_rel (root ,relid );
332+ int ojrelid = sjinfo -> ojrelid ;
333+ Relids joinrelids ;
334+ Relids join_plus_commute ;
338335List * joininfos ;
339336Index rti ;
340337ListCell * l ;
341338
339+ /* Compute the relid set for the join we are considering */
340+ joinrelids = bms_union (sjinfo -> min_lefthand ,sjinfo -> min_righthand );
341+ Assert (ojrelid != 0 );
342+ joinrelids = bms_add_member (joinrelids ,ojrelid );
343+
342344/*
343345 * Remove references to the rel from other baserels' attr_needed arrays.
344346 */
@@ -386,21 +388,21 @@ remove_rel_from_query(PlannerInfo *root, int relid, int ojrelid,
386388 */
387389foreach (l ,root -> join_info_list )
388390{
389- SpecialJoinInfo * sjinfo = (SpecialJoinInfo * )lfirst (l );
390-
391- sjinfo -> min_lefthand = bms_del_member (sjinfo -> min_lefthand ,relid );
392- sjinfo -> min_righthand = bms_del_member (sjinfo -> min_righthand ,relid );
393- sjinfo -> syn_lefthand = bms_del_member (sjinfo -> syn_lefthand ,relid );
394- sjinfo -> syn_righthand = bms_del_member (sjinfo -> syn_righthand ,relid );
395- sjinfo -> min_lefthand = bms_del_member (sjinfo -> min_lefthand ,ojrelid );
396- sjinfo -> min_righthand = bms_del_member (sjinfo -> min_righthand ,ojrelid );
397- sjinfo -> syn_lefthand = bms_del_member (sjinfo -> syn_lefthand ,ojrelid );
398- sjinfo -> syn_righthand = bms_del_member (sjinfo -> syn_righthand ,ojrelid );
391+ SpecialJoinInfo * sjinf = (SpecialJoinInfo * )lfirst (l );
392+
393+ sjinf -> min_lefthand = bms_del_member (sjinf -> min_lefthand ,relid );
394+ sjinf -> min_righthand = bms_del_member (sjinf -> min_righthand ,relid );
395+ sjinf -> syn_lefthand = bms_del_member (sjinf -> syn_lefthand ,relid );
396+ sjinf -> syn_righthand = bms_del_member (sjinf -> syn_righthand ,relid );
397+ sjinf -> min_lefthand = bms_del_member (sjinf -> min_lefthand ,ojrelid );
398+ sjinf -> min_righthand = bms_del_member (sjinf -> min_righthand ,ojrelid );
399+ sjinf -> syn_lefthand = bms_del_member (sjinf -> syn_lefthand ,ojrelid );
400+ sjinf -> syn_righthand = bms_del_member (sjinf -> syn_righthand ,ojrelid );
399401/* relid cannot appear in these fields, but ojrelid can: */
400- sjinfo -> commute_above_l = bms_del_member (sjinfo -> commute_above_l ,ojrelid );
401- sjinfo -> commute_above_r = bms_del_member (sjinfo -> commute_above_r ,ojrelid );
402- sjinfo -> commute_below_l = bms_del_member (sjinfo -> commute_below_l ,ojrelid );
403- sjinfo -> commute_below_r = bms_del_member (sjinfo -> commute_below_r ,ojrelid );
402+ sjinf -> commute_above_l = bms_del_member (sjinf -> commute_above_l ,ojrelid );
403+ sjinf -> commute_above_r = bms_del_member (sjinf -> commute_above_r ,ojrelid );
404+ sjinf -> commute_below_l = bms_del_member (sjinf -> commute_below_l ,ojrelid );
405+ sjinf -> commute_below_r = bms_del_member (sjinf -> commute_below_r ,ojrelid );
404406}
405407
406408/*
@@ -456,6 +458,18 @@ remove_rel_from_query(PlannerInfo *root, int relid, int ojrelid,
456458 * just discard them, though. Only quals that logically belonged to the
457459 * outer join being discarded should be removed from the query.
458460 *
461+ * We might encounter a qual that is a clone of a deletable qual with some
462+ * outer-join relids added (see deconstruct_distribute_oj_quals). To
463+ * ensure we get rid of such clones as well, add the relids of all OJs
464+ * commutable with this one to the set we test against for
465+ * pushed-down-ness.
466+ */
467+ join_plus_commute = bms_union (joinrelids ,
468+ sjinfo -> commute_above_r );
469+ join_plus_commute = bms_add_members (join_plus_commute ,
470+ sjinfo -> commute_below_l );
471+
472+ /*
459473 * We must make a copy of the rel's old joininfo list before starting the
460474 * loop, because otherwise remove_join_clause_from_rels would destroy the
461475 * list while we're scanning it.
@@ -467,15 +481,30 @@ remove_rel_from_query(PlannerInfo *root, int relid, int ojrelid,
467481
468482remove_join_clause_from_rels (root ,rinfo ,rinfo -> required_relids );
469483
470- if (RINFO_IS_PUSHED_DOWN (rinfo ,joinrelids ))
484+ if (RINFO_IS_PUSHED_DOWN (rinfo ,join_plus_commute ))
471485{
472486/*
473487 * There might be references to relid or ojrelid in the
474- * RestrictInfo, as a consequence of PHVs having ph_eval_at sets
475- * that include those. We already checked above that any such PHV
476- * is safe, so we can just drop those references.
488+ * RestrictInfo's relid sets, as a consequence of PHVs having had
489+ * ph_eval_at sets that include those. We already checked above
490+ * that any such PHV is safe (and updated its ph_eval_at), so we
491+ * can just drop those references.
477492 */
478493remove_rel_from_restrictinfo (rinfo ,relid ,ojrelid );
494+
495+ /*
496+ * Cross-check that the clause itself does not reference the
497+ * target rel or join.
498+ */
499+ #ifdef USE_ASSERT_CHECKING
500+ {
501+ Relids clause_varnos = pull_varnos (root ,
502+ (Node * )rinfo -> clause );
503+
504+ Assert (!bms_is_member (relid ,clause_varnos ));
505+ Assert (!bms_is_member (ojrelid ,clause_varnos ));
506+ }
507+ #endif
479508/* Now throw it back into the joininfo lists */
480509distribute_restrictinfo_to_rels (root ,rinfo );
481510}