Commit b2c51e6e authored by Tom Lane's avatar Tom Lane

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)
parent 4e03b827
$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
......
......@@ -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)
{
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment