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 ,
4141 int 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)
7373 foreach (lc , root -> join_info_list )
7474 {
7575 SpecialJoinInfo * sjinfo = (SpecialJoinInfo * ) lfirst (lc );
76- Relids joinrelids ;
7776 int innerrelid ;
7877 int nremoved ;
7978
@@ -88,12 +87,7 @@ remove_useless_joins(PlannerInfo *root, List *joinlist)
8887 */
8988 innerrelid = 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 */
9993 nremoved = 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{
337331 RelOptInfo * rel = find_base_rel (root , relid );
332+ int ojrelid = sjinfo -> ojrelid ;
333+ Relids joinrelids ;
334+ Relids join_plus_commute ;
338335 List * joininfos ;
339336 Index rti ;
340337 ListCell * 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 */
387389 foreach (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
468482 remove_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 */
478493 remove_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 */
480509 distribute_restrictinfo_to_rels (root , rinfo );
481510 }
0 commit comments