diff options
Diffstat (limited to 'src/backend/optimizer/path/joinrels.c')
-rw-r--r-- | src/backend/optimizer/path/joinrels.c | 97 |
1 files changed, 95 insertions, 2 deletions
diff --git a/src/backend/optimizer/path/joinrels.c b/src/backend/optimizer/path/joinrels.c index 8df5c21f1fd..7b8565db438 100644 --- a/src/backend/optimizer/path/joinrels.c +++ b/src/backend/optimizer/path/joinrels.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/path/joinrels.c,v 1.91 2008/01/11 04:02:18 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/path/joinrels.c,v 1.91.2.1 2008/03/24 21:53:12 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -27,6 +27,8 @@ static List *make_rels_by_clauseless_joins(PlannerInfo *root, ListCell *other_rels); static bool has_join_restriction(PlannerInfo *root, RelOptInfo *rel); static bool has_legal_joinclause(PlannerInfo *root, RelOptInfo *rel); +static bool is_dummy_rel(RelOptInfo *rel); +static void mark_dummy_join(RelOptInfo *rel); /* @@ -571,35 +573,75 @@ make_join_rel(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2) &restrictlist); /* - * Consider paths using each rel as both outer and inner. + * If we've already proven this join is empty, we needn't consider + * any more paths for it. + */ + if (is_dummy_rel(joinrel)) + { + bms_free(joinrelids); + return joinrel; + } + + /* + * Consider paths using each rel as both outer and inner. Depending + * on the join type, a provably empty outer or inner rel might mean + * the join is provably empty too; in which case throw away any + * previously computed paths and mark the join as dummy. (We do it + * this way since it's conceivable that dummy-ness of a multi-element + * join might only be noticeable for certain construction paths.) */ switch (jointype) { case JOIN_INNER: + if (is_dummy_rel(rel1) || is_dummy_rel(rel2)) + { + mark_dummy_join(joinrel); + break; + } add_paths_to_joinrel(root, joinrel, rel1, rel2, JOIN_INNER, restrictlist); add_paths_to_joinrel(root, joinrel, rel2, rel1, JOIN_INNER, restrictlist); break; case JOIN_LEFT: + if (is_dummy_rel(rel1)) + { + mark_dummy_join(joinrel); + break; + } add_paths_to_joinrel(root, joinrel, rel1, rel2, JOIN_LEFT, restrictlist); add_paths_to_joinrel(root, joinrel, rel2, rel1, JOIN_RIGHT, restrictlist); break; case JOIN_FULL: + if (is_dummy_rel(rel1) && is_dummy_rel(rel2)) + { + mark_dummy_join(joinrel); + break; + } add_paths_to_joinrel(root, joinrel, rel1, rel2, JOIN_FULL, restrictlist); add_paths_to_joinrel(root, joinrel, rel2, rel1, JOIN_FULL, restrictlist); break; case JOIN_RIGHT: + if (is_dummy_rel(rel2)) + { + mark_dummy_join(joinrel); + break; + } add_paths_to_joinrel(root, joinrel, rel1, rel2, JOIN_RIGHT, restrictlist); add_paths_to_joinrel(root, joinrel, rel2, rel1, JOIN_LEFT, restrictlist); break; case JOIN_IN: + if (is_dummy_rel(rel1) || is_dummy_rel(rel2)) + { + mark_dummy_join(joinrel); + break; + } add_paths_to_joinrel(root, joinrel, rel1, rel2, JOIN_IN, restrictlist); /* REVERSE_IN isn't supported by joinpath.c */ @@ -609,6 +651,11 @@ make_join_rel(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2) restrictlist); break; case JOIN_REVERSE_IN: + if (is_dummy_rel(rel1) || is_dummy_rel(rel2)) + { + mark_dummy_join(joinrel); + break; + } /* REVERSE_IN isn't supported by joinpath.c */ add_paths_to_joinrel(root, joinrel, rel2, rel1, JOIN_IN, restrictlist); @@ -618,12 +665,22 @@ make_join_rel(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2) restrictlist); break; case JOIN_UNIQUE_OUTER: + if (is_dummy_rel(rel1) || is_dummy_rel(rel2)) + { + mark_dummy_join(joinrel); + break; + } add_paths_to_joinrel(root, joinrel, rel1, rel2, JOIN_UNIQUE_OUTER, restrictlist); add_paths_to_joinrel(root, joinrel, rel2, rel1, JOIN_UNIQUE_INNER, restrictlist); break; case JOIN_UNIQUE_INNER: + if (is_dummy_rel(rel1) || is_dummy_rel(rel2)) + { + mark_dummy_join(joinrel); + break; + } add_paths_to_joinrel(root, joinrel, rel1, rel2, JOIN_UNIQUE_INNER, restrictlist); add_paths_to_joinrel(root, joinrel, rel2, rel1, JOIN_UNIQUE_OUTER, @@ -883,3 +940,39 @@ has_legal_joinclause(PlannerInfo *root, RelOptInfo *rel) return false; } + + +/* + * is_dummy_rel --- has relation been proven empty? + * + * If so, it will have a single path that is dummy. + */ +static bool +is_dummy_rel(RelOptInfo *rel) +{ + return (rel->cheapest_total_path != NULL && + IS_DUMMY_PATH(rel->cheapest_total_path)); +} + +/* + * Mark a joinrel as proven empty. + */ +static void +mark_dummy_join(RelOptInfo *rel) +{ + /* Set dummy size estimate */ + rel->rows = 0; + + /* Evict any previously chosen paths */ + rel->pathlist = NIL; + + /* Set up the dummy path */ + add_path(rel, (Path *) create_append_path(rel, NIL)); + + /* + * Although set_cheapest will be done again later, we do it immediately + * in order to keep is_dummy_rel as cheap as possible (ie, not have + * to examine the pathlist). + */ + set_cheapest(rel); +} |