]> granicus.if.org Git - postgresql/commitdiff
Support FULL JOIN with no join clauses, such as X FULL JOIN Y ON TRUE.
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 6 Apr 2004 18:46:03 +0000 (18:46 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 6 Apr 2004 18:46:03 +0000 (18:46 +0000)
That particular corner case is not exactly compelling, but given 7.4's
ability to discard redundant join clauses, it is possible for the situation
to arise from queries that are not so obviously silly.  Per bug report
of 6-Apr-04.

src/backend/optimizer/path/costsize.c
src/backend/optimizer/path/joinpath.c

index 79674ac4b94881a74c2efe343459d07c6f40183d..94ce4446fa27073a2e9b1cf98ee2699de78c9a3e 100644 (file)
@@ -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 */
index 8a666e80d8920dbae0e552e39fe0920d27804d63..ac6838d26e01fa604bed2305999b982f66bb2f11 100644 (file)
@@ -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;