Repair planner failure for cases involving Cartesian products inside
authorTom Lane
Sat, 24 Jan 2004 00:37:28 +0000 (00:37 +0000)
committerTom Lane
Sat, 24 Jan 2004 00:37:28 +0000 (00:37 +0000)
IN (sub-SELECT) constructs.  We must force a clauseless join of the
sub-select member relations, but it wasn't happening because the code
thought it would be able to use the join clause arising from the IN.

src/backend/optimizer/path/joinrels.c

index 26ff2e5758636e16f66cf5281b027d5979658778..50b9aef0110673ea83df0ddd1c9609ddcf85c84a 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/optimizer/path/joinrels.c,v 1.65 2003/12/17 17:07:48 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/optimizer/path/joinrels.c,v 1.66 2004/01/24 00:37:28 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -24,6 +24,7 @@ static List *make_rels_by_clause_joins(Query *root,
 static List *make_rels_by_clauseless_joins(Query *root,
                              RelOptInfo *old_rel,
                              List *other_rels);
+static bool is_inside_IN(Query *root, RelOptInfo *rel);
 
 
 /*
@@ -76,14 +77,26 @@ make_rels_by_joins(Query *root, int level, List **joinrels)
            /*
             * Note that if all available join clauses for this rel
             * require more than one other rel, we will fail to make any
-            * joins against it here.  That's OK; it'll be considered by
-            * "bushy plan" join code in a higher-level pass where we have
-            * those other rels collected into a join rel.  See also the
-            * last-ditch case below.
+            * joins against it here.  In most cases that's OK; it'll be
+            * considered by "bushy plan" join code in a higher-level pass
+            * where we have those other rels collected into a join rel.
             */
            new_rels = make_rels_by_clause_joins(root,
                                                 old_rel,
                                                 other_rels);
+           /*
+            * An exception occurs when there is a clauseless join inside an
+            * IN (sub-SELECT) construct.  Here, the members of the subselect
+            * all have join clauses (against the stuff outside the IN), but
+            * they *must* be joined to each other before we can make use of
+            * those join clauses.  So do the clauseless join bit.
+            *
+            * See also the last-ditch case below.
+            */
+           if (new_rels == NIL && is_inside_IN(root, old_rel))
+               new_rels = make_rels_by_clauseless_joins(root,
+                                                        old_rel,
+                                                        other_rels);
        }
        else
        {
@@ -347,6 +360,29 @@ make_rels_by_clauseless_joins(Query *root,
 }
 
 
+/*
+ * is_inside_IN
+ *     Detect whether the specified relation is inside an IN (sub-SELECT).
+ *
+ * Note that we are actually only interested in rels that have been pulled up
+ * out of an IN, so the routine name is a slight misnomer.
+ */
+static bool
+is_inside_IN(Query *root, RelOptInfo *rel)
+{
+   List       *i;
+
+   foreach(i, root->in_info_list)
+   {
+       InClauseInfo *ininfo = (InClauseInfo *) lfirst(i);
+
+       if (bms_is_subset(rel->relids, ininfo->righthand))
+           return true;
+   }
+   return false;
+}
+
+
 /*
  * make_jointree_rel
  *     Find or build a RelOptInfo join rel representing a specific