88 *
99 *
1010 * IDENTIFICATION
11- * $PostgreSQL: pgsql/src/backend/optimizer/plan/initsplan.c,v 1.123 2006/10/04 00:29:54 momjian Exp $
11+ * $PostgreSQL: pgsql/src/backend/optimizer/plan/initsplan.c,v 1.124 2006/12/07 19:33:40 tgl Exp $
1212 *
1313 *-------------------------------------------------------------------------
1414 */
@@ -735,30 +735,69 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
735735 * For a non-outer-join qual, we can evaluate the qual as soon as (1)
736736 * we have all the rels it mentions, and (2) we are at or above any
737737 * outer joins that can null any of these rels and are below the
738- * syntactic location of the given qual. To enforce the latter, scan
739- * the oj_info_list and merge the required-relid sets of any such OJs
740- * into the clause's own reference list. At the time we are called,
741- * the oj_info_list contains only outer joins below this qual.
738+ * syntactic location of the given qual. We must enforce (2) because
739+ * pushing down such a clause below the OJ might cause the OJ to emit
740+ * null-extended rows that should not have been formed, or that should
741+ * have been rejected by the clause. (This is only an issue for
742+ * non-strict quals, since if we can prove a qual mentioning only
743+ * nullable rels is strict, we'd have reduced the outer join to an
744+ * inner join in reduce_outer_joins().)
745+ *
746+ * To enforce (2), scan the oj_info_list and merge the required-relid
747+ * sets of any such OJs into the clause's own reference list. At the
748+ * time we are called, the oj_info_list contains only outer joins
749+ * below this qual. We have to repeat the scan until no new relids
750+ * get added; this ensures that the qual is suitably delayed regardless
751+ * of the order in which OJs get executed. As an example, if we have
752+ * one OJ with LHS=A, RHS=B, and one with LHS=B, RHS=C, it is implied
753+ * that these can be done in either order; if the B/C join is done
754+ * first then the join to A can null C, so a qual actually mentioning
755+ * only C cannot be applied below the join to A.
742756 */
743- Relids addrelids = NULL ;
744- ListCell * l ;
757+ bool found_some ;
745758
746759outerjoin_delayed = false;
747- foreach (l ,root -> oj_info_list )
748- {
749- OuterJoinInfo * ojinfo = (OuterJoinInfo * )lfirst (l );
760+ do {
761+ ListCell * l ;
750762
751- if (bms_overlap (relids ,ojinfo -> min_righthand )||
752- (ojinfo -> is_full_join &&
753- bms_overlap (relids ,ojinfo -> min_lefthand )))
763+ found_some = false;
764+ foreach (l ,root -> oj_info_list )
754765{
755- addrelids = bms_add_members (addrelids ,ojinfo -> min_lefthand );
756- addrelids = bms_add_members (addrelids ,ojinfo -> min_righthand );
757- outerjoin_delayed = true;
766+ OuterJoinInfo * ojinfo = (OuterJoinInfo * )lfirst (l );
767+
768+ /* do we have any nullable rels of this OJ? */
769+ if (bms_overlap (relids ,ojinfo -> min_righthand )||
770+ (ojinfo -> is_full_join &&
771+ bms_overlap (relids ,ojinfo -> min_lefthand )))
772+ {
773+ /* yes; do we have all its rels? */
774+ if (!bms_is_subset (ojinfo -> min_lefthand ,relids )||
775+ !bms_is_subset (ojinfo -> min_righthand ,relids ))
776+ {
777+ /* no, so add them in */
778+ relids = bms_add_members (relids ,
779+ ojinfo -> min_lefthand );
780+ relids = bms_add_members (relids ,
781+ ojinfo -> min_righthand );
782+ outerjoin_delayed = true;
783+ /* we'll need another iteration */
784+ found_some = true;
785+ }
786+ }
758787}
759- }
788+ }while ( found_some );
760789
761- if (bms_is_subset (addrelids ,relids ))
790+ if (outerjoin_delayed )
791+ {
792+ /* Should still be a subset of current scope ... */
793+ Assert (bms_is_subset (relids ,qualscope ));
794+ /*
795+ * Because application of the qual will be delayed by outer join,
796+ * we mustn't assume its vars are equal everywhere.
797+ */
798+ maybe_equijoin = false;
799+ }
800+ else
762801{
763802/*
764803 * Qual is not delayed by any lower outer-join restriction. If it
@@ -774,19 +813,8 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
774813else
775814maybe_equijoin = false;
776815}
777- else
778- {
779- relids = bms_union (relids ,addrelids );
780- /* Should still be a subset of current scope ... */
781- Assert (bms_is_subset (relids ,qualscope ));
782816
783- /*
784- * Because application of the qual will be delayed by outer join,
785- * we mustn't assume its vars are equal everywhere.
786- */
787- maybe_equijoin = false;
788- }
789- bms_free (addrelids );
817+ /* Since it doesn't mention the LHS, it's certainly not an OJ clause */
790818maybe_outer_join = false;
791819}
792820