Fix another semijoin-ordering bug. We already knew that we couldn't

reorder a semijoin into or out of the righthand side of another semijoin,
but actually it doesn't work to reorder it into or out of the righthand
side of a left or antijoin, either.  Per bug #4906 from Mathieu Fenniak.

This was sloppy thinking on my part.  This identity does work:

	( A left join B on (Pab) ) semijoin C on (Pac)
==
	( A semijoin C on (Pac) ) left join B on (Pab)

but I failed to see that that doesn't mean this does:

	( A left join B on (Pab) ) semijoin C on (Pbc)
!=
	A left join ( B semijoin C on (Pbc) ) on (Pab)
This commit is contained in:
Tom Lane 2009-07-21 02:02:44 +00:00
parent 4e03b827ee
commit b2c51e6eba
2 changed files with 11 additions and 10 deletions

View File

@ -1,4 +1,4 @@
$PostgreSQL: pgsql/src/backend/optimizer/README,v 1.49 2009/02/27 22:41:37 tgl Exp $
$PostgreSQL: pgsql/src/backend/optimizer/README,v 1.50 2009/07/21 02:02:44 tgl Exp $
Optimizer
=========
@ -214,10 +214,10 @@ out of the nullable side of an outer join:
!= (A leftjoin B on (Pab)) join C on (Pbc)
SEMI joins work a little bit differently. A semijoin can be reassociated
into or out of the lefthand side of another semijoin, but not into or out
of the righthand side. Likewise, an inner join, left join, or antijoin
can be reassociated into or out of the lefthand side of a semijoin, but
not into or out of the righthand side.
into or out of the lefthand side of another semijoin, left join, or
antijoin, but not into or out of the righthand side. Likewise, an inner
join, left join, or antijoin can be reassociated into or out of the
lefthand side of a semijoin, but not into or out of the righthand side.
ANTI joins work approximately like LEFT joins, except that identity 3
fails if the join to C is an antijoin (even if Pbc is strict, and in

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/plan/initsplan.c,v 1.154 2009/06/11 14:48:59 momjian Exp $
* $PostgreSQL: pgsql/src/backend/optimizer/plan/initsplan.c,v 1.155 2009/07/21 02:02:44 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -630,8 +630,8 @@ make_outerjoininfo(PlannerInfo *root,
* min_lefthand + min_righthand. This is because there might be other
* OJs below this one that this one can commute with, but we cannot
* commute with them if we don't with this one.) Also, if the current
* join is an antijoin, we must preserve ordering regardless of
* strictness.
* join is a semijoin or antijoin, we must preserve ordering
* regardless of strictness.
*
* Note: I believe we have to insist on being strict for at least one
* rel in the lower OJ's min_righthand, not its whole syn_righthand.
@ -639,7 +639,7 @@ make_outerjoininfo(PlannerInfo *root,
if (bms_overlap(left_rels, otherinfo->syn_righthand))
{
if (bms_overlap(clause_relids, otherinfo->syn_righthand) &&
(jointype == JOIN_ANTI ||
(jointype == JOIN_SEMI || jointype == JOIN_ANTI ||
!bms_overlap(strict_relids, otherinfo->min_righthand)))
{
min_lefthand = bms_add_members(min_lefthand,
@ -655,7 +655,7 @@ make_outerjoininfo(PlannerInfo *root,
* can interchange the ordering of the two OJs; otherwise we must add
* lower OJ's full syntactic relset to min_righthand. Here, we must
* preserve ordering anyway if either the current join is a semijoin,
* or the lower OJ is an antijoin.
* or the lower OJ is either a semijoin or an antijoin.
*
* Here, we have to consider that "our join condition" includes any
* clauses that syntactically appeared above the lower OJ and below
@ -672,6 +672,7 @@ make_outerjoininfo(PlannerInfo *root,
{
if (bms_overlap(clause_relids, otherinfo->syn_righthand) ||
jointype == JOIN_SEMI ||
otherinfo->jointype == JOIN_SEMI ||
otherinfo->jointype == JOIN_ANTI ||
!otherinfo->lhs_strict || otherinfo->delay_upper_joins)
{