Skip to content

Commit ddb4015

Browse files
committed
Fix longstanding bug that would sometimes let the planner generate a bad plan
for an outer join; symptom is bogus error "RIGHT JOIN is only supported with merge-joinable join conditions". Problem was that select_mergejoin_clauses did its tests in the wrong order. We need to force left join not right join for a merge join when there are non-mergeable join clauses; but the test for this only accounted for mergejoinability of the clause operator, and not whether the left and right Vars were of the proper relations. Per report from Jean-Pierre Pelletier.
1 parent 62cfa0f commit ddb4015

File tree

1 file changed

+37
-32
lines changed

1 file changed

+37
-32
lines changed

src/backend/optimizer/path/joinpath.c

Lines changed: 37 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/optimizer/path/joinpath.c,v 1.96 2005/10/15 02:49:20 momjian Exp $
11+
* $PostgreSQL: pgsql/src/backend/optimizer/path/joinpath.c,v 1.97 2005/10/25 20:30:30 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -795,6 +795,7 @@ select_mergejoin_clauses(RelOptInfo *joinrel,
795795
{
796796
List *result_list = NIL;
797797
bool isouterjoin = IS_OUTER_JOIN(jointype);
798+
bool have_nonmergeable_joinclause = false;
798799
ListCell *l;
799800

800801
foreach(l, restrictlist)
@@ -803,42 +804,19 @@ select_mergejoin_clauses(RelOptInfo *joinrel,
803804

804805
/*
805806
* If processing an outer join, only use its own join clauses in the
806-
* merge. For inner joins we need not be so picky.
807-
*
808-
* Furthermore, if it is a right/full join then *all* the explicit join
809-
* clauses must be mergejoinable, else the executor will fail. If we
810-
* are asked for a right join then just return NIL to indicate no
811-
* mergejoin is possible (we can handle it as a left join instead). If
812-
* we are asked for a full join then emit an error, because there is
813-
* no fallback.
807+
* merge. For inner joins we can use pushed-down clauses too.
808+
* (Note: we don't set have_nonmergeable_joinclause here because
809+
* pushed-down clauses will become otherquals not joinquals.)
814810
*/
815-
if (isouterjoin)
816-
{
817-
if (restrictinfo->is_pushed_down)
818-
continue;
819-
switch (jointype)
820-
{
821-
case JOIN_RIGHT:
822-
if (!restrictinfo->can_join ||
823-
restrictinfo->mergejoinoperator == InvalidOid)
824-
return NIL; /* not mergejoinable */
825-
break;
826-
case JOIN_FULL:
827-
if (!restrictinfo->can_join ||
828-
restrictinfo->mergejoinoperator == InvalidOid)
829-
ereport(ERROR,
830-
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
831-
errmsg("FULL JOIN is only supported with merge-joinable join conditions")));
832-
break;
833-
default:
834-
/* otherwise, it's OK to have nonmergeable join quals */
835-
break;
836-
}
837-
}
811+
if (isouterjoin && restrictinfo->is_pushed_down)
812+
continue;
838813

839814
if (!restrictinfo->can_join ||
840815
restrictinfo->mergejoinoperator == InvalidOid)
816+
{
817+
have_nonmergeable_joinclause = true;
841818
continue; /* not mergejoinable */
819+
}
842820

843821
/*
844822
* Check if clause is usable with these input rels. All the vars
@@ -856,10 +834,37 @@ select_mergejoin_clauses(RelOptInfo *joinrel,
856834
/* lefthand side is inner */
857835
}
858836
else
837+
{
838+
have_nonmergeable_joinclause = true;
859839
continue; /* no good for these input relations */
840+
}
860841

861842
result_list = lcons(restrictinfo, result_list);
862843
}
863844

845+
/*
846+
* If it is a right/full join then *all* the explicit join clauses must be
847+
* mergejoinable, else the executor will fail. If we are asked for a right
848+
* join then just return NIL to indicate no mergejoin is possible (we can
849+
* handle it as a left join instead). If we are asked for a full join then
850+
* emit an error, because there is no fallback.
851+
*/
852+
if (have_nonmergeable_joinclause)
853+
{
854+
switch (jointype)
855+
{
856+
case JOIN_RIGHT:
857+
return NIL; /* not mergejoinable */
858+
case JOIN_FULL:
859+
ereport(ERROR,
860+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
861+
errmsg("FULL JOIN is only supported with merge-joinable join conditions")));
862+
break;
863+
default:
864+
/* otherwise, it's OK to have nonmergeable join quals */
865+
break;
866+
}
867+
}
868+
864869
return result_list;
865870
}

0 commit comments

Comments
 (0)