8
8
*
9
9
*
10
10
* 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 $
12
12
*
13
13
*-------------------------------------------------------------------------
14
14
*/
@@ -735,30 +735,69 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
735
735
* For a non-outer-join qual, we can evaluate the qual as soon as (1)
736
736
* we have all the rels it mentions, and (2) we are at or above any
737
737
* 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.
742
756
*/
743
- Relids addrelids = NULL ;
744
- ListCell * l ;
757
+ bool found_some ;
745
758
746
759
outerjoin_delayed = false;
747
- foreach (l , root -> oj_info_list )
748
- {
749
- OuterJoinInfo * ojinfo = (OuterJoinInfo * ) lfirst (l );
760
+ do {
761
+ ListCell * l ;
750
762
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 )
754
765
{
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
+ }
758
787
}
759
- }
788
+ } while ( found_some );
760
789
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
762
801
{
763
802
/*
764
803
* Qual is not delayed by any lower outer-join restriction. If it
@@ -774,19 +813,8 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
774
813
else
775
814
maybe_equijoin = false;
776
815
}
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 ));
782
816
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 */
790
818
maybe_outer_join = false;
791
819
}
792
820
0 commit comments