diff --git a/src/backend/optimizer/path/joinpath.c b/src/backend/optimizer/path/joinpath.c index bfd246388b441aa283e7d846b1635a3b3c88f1db..d41336ddcee0f9c26ad9a2ab0b1410a1f0ae38c7 100644 --- a/src/backend/optimizer/path/joinpath.c +++ b/src/backend/optimizer/path/joinpath.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/path/joinpath.c,v 1.62 2001/03/22 03:59:35 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/path/joinpath.c,v 1.63 2001/04/15 00:48:17 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -290,20 +290,34 @@ match_unsorted_outer(Query *root, JoinType jointype) { bool nestjoinOK; + bool useallclauses; Path *bestinnerjoin; List *i; /* - * Nestloop only supports inner and left joins. + * Nestloop only supports inner and left joins. Also, if we are doing + * a right or full join, we must use *all* the mergeclauses as join + * clauses, else we will not have a valid plan. (Although these two flags + * are currently inverses, keep them separate for clarity and possible + * future changes.) */ switch (jointype) { case JOIN_INNER: case JOIN_LEFT: nestjoinOK = true; + useallclauses = false; break; - default: + case JOIN_RIGHT: + case JOIN_FULL: nestjoinOK = false; + useallclauses = true; + break; + default: + elog(ERROR, "match_unsorted_outer: unexpected join type %d", + (int) jointype); + nestjoinOK = false; /* keep compiler quiet */ + useallclauses = false; break; } @@ -339,8 +353,8 @@ match_unsorted_outer(Query *root, /* * Always consider a nestloop join with this outer and - * cheapest- total-cost inner. Consider nestloops using the - * cheapest- startup-cost inner as well, and the best + * cheapest-total-cost inner. Consider nestloops using the + * cheapest-startup-cost inner as well, and the best * innerjoin indexpath. */ add_path(joinrel, (Path *) @@ -377,6 +391,8 @@ match_unsorted_outer(Query *root, /* Done with this outer path if no chance for a mergejoin */ if (mergeclauses == NIL) continue; + if (useallclauses && length(mergeclauses) != length(mergeclause_list)) + continue; /* Compute the required ordering of the inner path */ innersortkeys = make_pathkeys_for_mergeclauses(root, @@ -402,13 +418,14 @@ match_unsorted_outer(Query *root, /* * Look for presorted inner paths that satisfy the innersortkey - * list or any truncation thereof. Here, we consider both cheap - * startup cost and cheap total cost. Ignore + * list --- or any truncation thereof, if we are allowed to build + * a mergejoin using a subset of the merge clauses. Here, we + * consider both cheap startup cost and cheap total cost. Ignore * innerrel->cheapest_total_path, since we already made a path * with it. */ num_sortkeys = length(innersortkeys); - if (num_sortkeys > 1) + if (num_sortkeys > 1 && !useallclauses) trialsortkeys = listCopy(innersortkeys); /* need modifiable copy */ else trialsortkeys = innersortkeys; /* won't really truncate */ @@ -503,6 +520,11 @@ match_unsorted_outer(Query *root, } cheapest_startup_inner = innerpath; } + /* + * Don't consider truncated sortkeys if we need all clauses. + */ + if (useallclauses) + break; } } } @@ -532,8 +554,26 @@ match_unsorted_inner(Query *root, List *mergeclause_list, JoinType jointype) { + bool useallclauses; List *i; + switch (jointype) + { + case JOIN_INNER: + case JOIN_LEFT: + useallclauses = false; + break; + case JOIN_RIGHT: + case JOIN_FULL: + useallclauses = true; + break; + default: + elog(ERROR, "match_unsorted_inner: unexpected join type %d", + (int) jointype); + useallclauses = false; /* keep compiler quiet */ + break; + } + foreach(i, innerrel->pathlist) { Path *innerpath = (Path *) lfirst(i); @@ -547,8 +587,12 @@ match_unsorted_inner(Query *root, mergeclauses = find_mergeclauses_for_pathkeys(root, innerpath->pathkeys, mergeclause_list); + + /* Done with this inner path if no chance for a mergejoin */ if (mergeclauses == NIL) continue; + if (useallclauses && length(mergeclauses) != length(mergeclause_list)) + continue; /* Compute the required ordering of the outer path */ outersortkeys = make_pathkeys_for_mergeclauses(root,