Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 8124215

Browse files
committed
Repair incorrect placement of WHERE clauses when there are multiple,
rearrangeable outer joins and the WHERE clause is non-strict and mentions only nullable-side relations. New bug in 8.2, caused by new logic to allow rearranging outer joins. Per bug #2807 from Ross Cohen; thanks to Jeff Davis for producing a usable test case.
1 parent b307d7a commit 8124215

File tree

1 file changed

+58
-30
lines changed

1 file changed

+58
-30
lines changed

src/backend/optimizer/plan/initsplan.c

Lines changed: 58 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
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

746759
outerjoin_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,
774813
else
775814
maybe_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 */
790818
maybe_outer_join = false;
791819
}
792820

0 commit comments

Comments
 (0)