35
35
36
36
/* local functions */
37
37
static 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 );
40
40
static void remove_rel_from_restrictinfo (RestrictInfo * rinfo ,
41
41
int relid , int ojrelid );
42
42
static List * remove_rel_from_joinlist (List * joinlist , int relid , int * nremoved );
@@ -73,7 +73,6 @@ remove_useless_joins(PlannerInfo *root, List *joinlist)
73
73
foreach (lc , root -> join_info_list )
74
74
{
75
75
SpecialJoinInfo * sjinfo = (SpecialJoinInfo * ) lfirst (lc );
76
- Relids joinrelids ;
77
76
int innerrelid ;
78
77
int nremoved ;
79
78
@@ -88,12 +87,7 @@ remove_useless_joins(PlannerInfo *root, List *joinlist)
88
87
*/
89
88
innerrelid = bms_singleton_member (sjinfo -> min_righthand );
90
89
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 );
97
91
98
92
/* We verify that exactly one reference gets removed from joinlist */
99
93
nremoved = 0 ;
@@ -324,21 +318,29 @@ join_is_removable(PlannerInfo *root, SpecialJoinInfo *sjinfo)
324
318
325
319
326
320
/*
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.
329
324
*
330
325
* We are not terribly thorough here. We only bother to update parts of
331
326
* the planner's data structures that will actually be consulted later.
332
327
*/
333
328
static 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 )
336
330
{
337
331
RelOptInfo * rel = find_base_rel (root , relid );
332
+ int ojrelid = sjinfo -> ojrelid ;
333
+ Relids joinrelids ;
334
+ Relids join_plus_commute ;
338
335
List * joininfos ;
339
336
Index rti ;
340
337
ListCell * l ;
341
338
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
+
342
344
/*
343
345
* Remove references to the rel from other baserels' attr_needed arrays.
344
346
*/
@@ -386,21 +388,21 @@ remove_rel_from_query(PlannerInfo *root, int relid, int ojrelid,
386
388
*/
387
389
foreach (l , root -> join_info_list )
388
390
{
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 );
399
401
/* 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 );
404
406
}
405
407
406
408
/*
@@ -456,6 +458,18 @@ remove_rel_from_query(PlannerInfo *root, int relid, int ojrelid,
456
458
* just discard them, though. Only quals that logically belonged to the
457
459
* outer join being discarded should be removed from the query.
458
460
*
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
+ /*
459
473
* We must make a copy of the rel's old joininfo list before starting the
460
474
* loop, because otherwise remove_join_clause_from_rels would destroy the
461
475
* list while we're scanning it.
@@ -467,15 +481,30 @@ remove_rel_from_query(PlannerInfo *root, int relid, int ojrelid,
467
481
468
482
remove_join_clause_from_rels (root , rinfo , rinfo -> required_relids );
469
483
470
- if (RINFO_IS_PUSHED_DOWN (rinfo , joinrelids ))
484
+ if (RINFO_IS_PUSHED_DOWN (rinfo , join_plus_commute ))
471
485
{
472
486
/*
473
487
* 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.
477
492
*/
478
493
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
479
508
/* Now throw it back into the joininfo lists */
480
509
distribute_restrictinfo_to_rels (root , rinfo );
481
510
}
0 commit comments