diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2004-01-24 00:37:42 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2004-01-24 00:37:42 +0000 |
commit | 67a1bf1bb11ad1a916725f3bc788c5b777326b4d (patch) | |
tree | 09237f29169051b2a36ae1ea5936255999e39c0b | |
parent | 052cd647c79a2c41811b6c2b91bcfe0365d66b72 (diff) | |
download | postgresql-67a1bf1bb11ad1a916725f3bc788c5b777326b4d.tar.gz postgresql-67a1bf1bb11ad1a916725f3bc788c5b777326b4d.zip |
Repair planner failure for cases involving Cartesian products inside
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.
-rw-r--r-- | src/backend/optimizer/path/joinrels.c | 46 |
1 files changed, 41 insertions, 5 deletions
diff --git a/src/backend/optimizer/path/joinrels.c b/src/backend/optimizer/path/joinrels.c index 07345d275d5..038e6bee742 100644 --- a/src/backend/optimizer/path/joinrels.c +++ b/src/backend/optimizer/path/joinrels.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/path/joinrels.c,v 1.63.4.1 2003/12/17 17:08:06 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/path/joinrels.c,v 1.63.4.2 2004/01/24 00:37:42 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 { @@ -348,6 +361,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 * jointree item. For JoinExprs, we only consider the construction |