diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c index 79674ac4b94881a74c2efe343459d07c6f40183d..94ce4446fa27073a2e9b1cf98ee2699de78c9a3e 100644 --- a/src/backend/optimizer/path/costsize.c +++ b/src/backend/optimizer/path/costsize.c @@ -49,7 +49,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.125 2004/02/17 00:52:53 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.126 2004/04/06 18:46:03 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -918,23 +918,31 @@ cost_mergejoin(MergePath *path, Query *root) * all mergejoin paths associated with the merge clause, we cache the * results in the RestrictInfo node. */ - firstclause = (RestrictInfo *) lfirst(mergeclauses); - if (firstclause->left_mergescansel < 0) /* not computed yet? */ - mergejoinscansel(root, (Node *) firstclause->clause, - &firstclause->left_mergescansel, - &firstclause->right_mergescansel); - - if (bms_is_subset(firstclause->left_relids, outer_path->parent->relids)) + if (mergeclauses) { - /* left side of clause is outer */ - outerscansel = firstclause->left_mergescansel; - innerscansel = firstclause->right_mergescansel; + firstclause = (RestrictInfo *) lfirst(mergeclauses); + if (firstclause->left_mergescansel < 0) /* not computed yet? */ + mergejoinscansel(root, (Node *) firstclause->clause, + &firstclause->left_mergescansel, + &firstclause->right_mergescansel); + + if (bms_is_subset(firstclause->left_relids, outer_path->parent->relids)) + { + /* left side of clause is outer */ + outerscansel = firstclause->left_mergescansel; + innerscansel = firstclause->right_mergescansel; + } + else + { + /* left side of clause is inner */ + outerscansel = firstclause->right_mergescansel; + innerscansel = firstclause->left_mergescansel; + } } else { - /* left side of clause is inner */ - outerscansel = firstclause->right_mergescansel; - innerscansel = firstclause->left_mergescansel; + /* cope with clauseless mergejoin */ + outerscansel = innerscansel = 1.0; } /* convert selectivity to row count; must scan at least one row */ diff --git a/src/backend/optimizer/path/joinpath.c b/src/backend/optimizer/path/joinpath.c index 8a666e80d8920dbae0e552e39fe0920d27804d63..ac6838d26e01fa604bed2305999b982f66bb2f11 100644 --- a/src/backend/optimizer/path/joinpath.c +++ b/src/backend/optimizer/path/joinpath.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/path/joinpath.c,v 1.85 2004/01/05 05:07:35 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/path/joinpath.c,v 1.86 2004/04/06 18:46:03 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -489,9 +489,27 @@ match_unsorted_outer(Query *root, outerpath->pathkeys, mergeclause_list); - /* Done with this outer path if no chance for a mergejoin */ + /* + * Done with this outer path if no chance for a mergejoin. + * + * Special corner case: for "x FULL JOIN y ON true", there will be + * no join clauses at all. Ordinarily we'd generate a clauseless + * nestloop path, but since mergejoin is our only join type that + * supports FULL JOIN, it's necessary to generate a clauseless + * mergejoin path instead. + * + * Unfortunately this can't easily be extended to handle the case + * where there are joinclauses but none of them use mergejoinable + * operators; nodeMergejoin.c can only do a full join correctly if + * all the joinclauses are mergeclauses. + */ if (mergeclauses == NIL) - continue; + { + if (jointype == JOIN_FULL && restrictlist == NIL) + /* okay to try for mergejoin */ ; + else + continue; + } if (useallclauses && length(mergeclauses) != length(mergeclause_list)) continue;