Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit c5c9731

Browse files
committed
In find_mergeclauses_for_pathkeys, it's okay to return multiple merge
clauses per path key. Indeed, we *must* do so or we will be unable to form a valid plan for FULL JOIN with overlapping join conditions, eg select * from a full join b on a.v1 = b.v1 and a.v2 = b.v2 and a.v1 = b.v2.
1 parent c336b58 commit c5c9731

File tree

1 file changed

+32
-14
lines changed

1 file changed

+32
-14
lines changed

src/backend/optimizer/path/pathkeys.c

+32-14
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
* Portions Copyright (c) 1994, Regents of the University of California
1212
*
1313
* IDENTIFICATION
14-
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/pathkeys.c,v 1.35 2001/10/28 06:25:44 momjian Exp $
14+
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/pathkeys.c,v 1.36 2001/11/11 20:33:53 tgl Exp $
1515
*
1616
*-------------------------------------------------------------------------
1717
*/
@@ -752,25 +752,43 @@ find_mergeclauses_for_pathkeys(Query *root,
752752
List *mergeclauses = NIL;
753753
List *i;
754754

755+
/* make sure we have pathkeys cached in the clauses */
756+
foreach(i, restrictinfos)
757+
{
758+
RestrictInfo *restrictinfo = lfirst(i);
759+
760+
cache_mergeclause_pathkeys(root, restrictinfo);
761+
}
762+
755763
foreach(i, pathkeys)
756764
{
757765
List *pathkey = lfirst(i);
758-
RestrictInfo *matched_restrictinfo = NULL;
766+
List *matched_restrictinfos = NIL;
759767
List *j;
760768

761769
/*
762770
* We can match a pathkey against either left or right side of any
763-
* mergejoin clause we haven't used yet. For the moment we use a
764-
* dumb "greedy" algorithm with no backtracking. Is it worth
765-
* being any smarter to make a longer list of usable mergeclauses?
766-
* Probably not.
771+
* mergejoin clause. (We examine both sides since we aren't told if
772+
* the given pathkeys are for inner or outer input path; no confusion
773+
* is possible.) Furthermore, if there are multiple matching
774+
* clauses, take them all. In plain inner-join scenarios we expect
775+
* only one match, because redundant-mergeclause elimination will
776+
* have removed any redundant mergeclauses from the input list.
777+
* However, in outer-join scenarios there might be multiple matches.
778+
* An example is
779+
*
780+
* select * from a full join b on
781+
* a.v1 = b.v1 and a.v2 = b.v2 and a.v1 = b.v2;
782+
*
783+
* Given the pathkeys ((a.v1), (a.v2)) it is okay to return all
784+
* three clauses (in the order a.v1=b.v1, a.v1=b.v2, a.v2=b.v2)
785+
* and indeed we *must* do so or we will be unable to form a
786+
* valid plan.
767787
*/
768788
foreach(j, restrictinfos)
769789
{
770790
RestrictInfo *restrictinfo = lfirst(j);
771791

772-
cache_mergeclause_pathkeys(root, restrictinfo);
773-
774792
/*
775793
* We can compare canonical pathkey sublists by simple pointer
776794
* equality; see compare_pathkeys.
@@ -779,8 +797,8 @@ find_mergeclauses_for_pathkeys(Query *root,
779797
pathkey == restrictinfo->right_pathkey) &&
780798
!ptrMember(restrictinfo, mergeclauses))
781799
{
782-
matched_restrictinfo = restrictinfo;
783-
break;
800+
matched_restrictinfos = lappend(matched_restrictinfos,
801+
restrictinfo);
784802
}
785803
}
786804

@@ -789,14 +807,14 @@ find_mergeclauses_for_pathkeys(Query *root,
789807
* sort-key positions in the pathkeys are useless. (But we can
790808
* still mergejoin if we found at least one mergeclause.)
791809
*/
792-
if (!matched_restrictinfo)
810+
if (matched_restrictinfos == NIL)
793811
break;
794812

795813
/*
796-
* If we did find a usable mergeclause for this sort-key position,
797-
* add it to result list.
814+
* If we did find usable mergeclause(s) for this sort-key position,
815+
* add them to result list.
798816
*/
799-
mergeclauses = lappend(mergeclauses, matched_restrictinfo);
817+
mergeclauses = nconc(mergeclauses, matched_restrictinfos);
800818
}
801819

802820
return mergeclauses;

0 commit comments

Comments
 (0)