88 *
99 *
1010 * IDENTIFICATION
11- * $PostgreSQL: pgsql/src/backend/optimizer/plan/initsplan.c,v 1.131 2007/02/16 20:57:19 tgl Exp $
11+ * $PostgreSQL: pgsql/src/backend/optimizer/plan/initsplan.c,v 1.132 2007/05/22 23:23:56 tgl Exp $
1212 *
1313 *-------------------------------------------------------------------------
1414 */
@@ -48,7 +48,8 @@ static void distribute_qual_to_rels(PlannerInfo *root, Node *clause,
4848 Relids qualscope ,
4949 Relids ojscope ,
5050 Relids outerjoin_nonnullable );
51- static bool check_outerjoin_delay (PlannerInfo * root , Relids * relids_p );
51+ static bool check_outerjoin_delay (PlannerInfo * root , Relids * relids_p ,
52+ bool is_pushed_down );
5253static void check_mergejoinable (RestrictInfo * restrictinfo );
5354static void check_hashjoinable (RestrictInfo * restrictinfo );
5455
@@ -492,6 +493,9 @@ make_outerjoininfo(PlannerInfo *root,
492493 errmsg ("SELECT FOR UPDATE/SHARE cannot be applied to the nullable side of an outer join" )));
493494 }
494495
496+ /* this always starts out false */
497+ ojinfo -> delay_upper_joins = false;
498+
495499 /* If it's a full join, no need to be very smart */
496500 ojinfo -> is_full_join = is_full_join ;
497501 if (is_full_join )
@@ -561,10 +565,21 @@ make_outerjoininfo(PlannerInfo *root,
561565 * lower join's RHS and the lower OJ's join condition is strict, we
562566 * can interchange the ordering of the two OJs, so exclude the lower
563567 * RHS from our min_righthand.
568+ *
569+ * Here, we have to consider that "our join condition" includes
570+ * any clauses that syntactically appeared above the lower OJ and
571+ * below ours; those are equivalent to degenerate clauses in our
572+ * OJ and must be treated as such. Such clauses obviously can't
573+ * reference our LHS, and they must be non-strict for the lower OJ's
574+ * RHS (else reduce_outer_joins would have reduced the lower OJ to
575+ * a plain join). Hence the other ways in which we handle clauses
576+ * within our join condition are not affected by them. The net
577+ * effect is therefore sufficiently represented by the
578+ * delay_upper_joins flag saved for us by check_outerjoin_delay.
564579 */
565580 if (bms_overlap (ojinfo -> min_righthand , otherinfo -> min_righthand ) &&
566581 !bms_overlap (clause_relids , otherinfo -> min_righthand ) &&
567- otherinfo -> lhs_strict )
582+ otherinfo -> lhs_strict && ! otherinfo -> delay_upper_joins )
568583 {
569584 ojinfo -> min_righthand = bms_del_members (ojinfo -> min_righthand ,
570585 otherinfo -> min_righthand );
@@ -749,7 +764,7 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
749764 * clauses.
750765 */
751766 maybe_equivalence = false;
752- maybe_outer_join = !check_outerjoin_delay (root , & relids );
767+ maybe_outer_join = !check_outerjoin_delay (root , & relids , false );
753768
754769 /*
755770 * Now force the qual to be evaluated exactly at the level of joining
@@ -776,7 +791,7 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
776791 is_pushed_down = true;
777792
778793 /* Check to see if must be delayed by outer join */
779- outerjoin_delayed = check_outerjoin_delay (root , & relids );
794+ outerjoin_delayed = check_outerjoin_delay (root , & relids , true );
780795
781796 if (outerjoin_delayed )
782797 {
@@ -918,10 +933,13 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
918933/*
919934 * check_outerjoin_delay
920935 * Detect whether a qual referencing the given relids must be delayed
921- * in application due to the presence of a lower outer join.
936+ * in application due to the presence of a lower outer join, and/or
937+ * may force extra delay of higher-level outer joins.
922938 *
923- * If so, add relids to *relids_p to reflect the lowest safe level for
924- * evaluating the qual, and return TRUE.
939+ * If the qual must be delayed, add relids to *relids_p to reflect the lowest
940+ * safe level for evaluating the qual, and return TRUE. Any extra delay for
941+ * higher-level joins is reflected by setting delay_upper_joins to TRUE in
942+ * OuterJoinInfo structs.
925943 *
926944 * For an is_pushed_down qual, we can evaluate the qual as soon as (1) we have
927945 * all the rels it mentions, and (2) we are at or above any outer joins that
@@ -946,9 +964,23 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
946964 * For a non-pushed-down qual, this isn't going to determine where we place the
947965 * qual, but we need to determine outerjoin_delayed anyway so we can decide
948966 * whether the qual is potentially useful for equivalence deductions.
967+ *
968+ * Lastly, a pushed-down qual that references the nullable side of any current
969+ * oj_info_list member and has to be evaluated above that OJ (because its
970+ * required relids overlap the LHS too) causes that OJ's delay_upper_joins
971+ * flag to be set TRUE. This will prevent any higher-level OJs from
972+ * being interchanged with that OJ, which would result in not having any
973+ * correct place to evaluate the qual. (The case we care about here is a
974+ * sub-select WHERE clause within the RHS of some outer join. The WHERE
975+ * clause must effectively be treated as a degenerate clause of that outer
976+ * join's condition. Rather than trying to match such clauses with joins
977+ * directly, we set delay_upper_joins here, and when the upper outer join
978+ * is processed by make_outerjoininfo, it will refrain from allowing the
979+ * two OJs to commute.)
949980 */
950981static bool
951- check_outerjoin_delay (PlannerInfo * root , Relids * relids_p )
982+ check_outerjoin_delay (PlannerInfo * root , Relids * relids_p ,
983+ bool is_pushed_down )
952984{
953985 Relids relids = * relids_p ;
954986 bool outerjoin_delayed ;
@@ -979,6 +1011,10 @@ check_outerjoin_delay(PlannerInfo *root, Relids *relids_p)
9791011 /* we'll need another iteration */
9801012 found_some = true;
9811013 }
1014+ /* set delay_upper_joins if needed */
1015+ if (is_pushed_down && !ojinfo -> is_full_join &&
1016+ bms_overlap (relids , ojinfo -> min_lefthand ))
1017+ ojinfo -> delay_upper_joins = true;
9821018 }
9831019 }
9841020 } while (found_some );
0 commit comments