diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c index 4b500bc03a5..c151ddd5f16 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 - * $Header: /cvsroot/pgsql/src/backend/optimizer/path/costsize.c,v 1.115.2.1 2003/12/03 17:45:36 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/path/costsize.c,v 1.115.2.2 2004/04/06 18:46:25 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -928,23 +928,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 174c83cd211..956dd991cd6 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.82 2003/09/25 06:58:00 petere Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/path/joinpath.c,v 1.82.2.1 2004/04/06 18:46:25 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;