diff options
Diffstat (limited to 'src/backend/optimizer/plan')
| -rw-r--r-- | src/backend/optimizer/plan/createplan.c | 5 | ||||
| -rw-r--r-- | src/backend/optimizer/plan/initsplan.c | 111 | ||||
| -rw-r--r-- | src/backend/optimizer/plan/planmain.c | 5 | ||||
| -rw-r--r-- | src/backend/optimizer/plan/planner.c | 17 |
4 files changed, 91 insertions, 47 deletions
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index 76812e2e4b..959c17206c 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.192 2005/06/10 22:25:36 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.193 2005/07/02 23:00:41 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1176,8 +1176,7 @@ create_nestloop_plan(PlannerInfo *root, List *bitmapclauses; bitmapclauses = - make_restrictinfo_from_bitmapqual(innerpath->bitmapqual, - true, true); + make_restrictinfo_from_bitmapqual(innerpath->bitmapqual, true); joinrestrictclauses = select_nonredundant_join_clauses(root, joinrestrictclauses, diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c index f7066e4906..91a23d6d1c 100644 --- a/src/backend/optimizer/plan/initsplan.c +++ b/src/backend/optimizer/plan/initsplan.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/plan/initsplan.c,v 1.107 2005/06/09 04:18:59 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/plan/initsplan.c,v 1.108 2005/07/02 23:00:41 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -374,8 +374,8 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause, Relids qualscope) { Relids relids; - bool valid_everywhere; - bool can_be_equijoin; + bool maybe_equijoin; + bool maybe_outer_join; RestrictInfo *restrictinfo; RelOptInfo *rel; List *vars; @@ -409,14 +409,15 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause, if (isdeduced) { /* - * If the qual came from implied-equality deduction, we can - * evaluate the qual at its natural semantic level. It is not - * affected by any outer-join rules (else we'd not have decided - * the vars were equal). + * If the qual came from implied-equality deduction, we always + * evaluate the qual at its natural semantic level. It is the + * responsibility of the deducer not to create any quals that + * should be delayed by outer-join rules. */ Assert(bms_equal(relids, qualscope)); - valid_everywhere = true; - can_be_equijoin = true; + /* Needn't feed it back for more deductions */ + maybe_equijoin = false; + maybe_outer_join = false; } else if (bms_overlap(relids, outerjoin_nonnullable)) { @@ -434,8 +435,14 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause, * result, so we treat it the same as an ordinary inner-join qual. */ relids = qualscope; - valid_everywhere = false; - can_be_equijoin = false; + /* + * We can't use such a clause to deduce equijoin (the left and + * right sides might be unequal above the join because one of + * them has gone to NULL) ... but we might be able to use it + * for more limited purposes. + */ + maybe_equijoin = false; + maybe_outer_join = true; } else { @@ -449,34 +456,25 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause, * time we are called, the outerjoinset of each baserel will show * exactly those outer joins that are below the qual in the join * tree. - * - * We also need to determine whether the qual is "valid everywhere", - * which is true if the qual mentions no variables that are - * involved in lower-level outer joins (this may be an overly - * strong test). */ Relids addrelids = NULL; Relids tmprelids; int relno; - valid_everywhere = true; tmprelids = bms_copy(relids); while ((relno = bms_first_member(tmprelids)) >= 0) { RelOptInfo *rel = find_base_rel(root, relno); if (rel->outerjoinset != NULL) - { addrelids = bms_add_members(addrelids, rel->outerjoinset); - valid_everywhere = false; - } } bms_free(tmprelids); if (bms_is_subset(addrelids, relids)) { /* Qual is not affected by any outer-join restriction */ - can_be_equijoin = true; + maybe_equijoin = true; } else { @@ -488,9 +486,10 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause, * Because application of the qual will be delayed by outer * join, we mustn't assume its vars are equal everywhere. */ - can_be_equijoin = false; + maybe_equijoin = false; } bms_free(addrelids); + maybe_outer_join = false; } /* @@ -508,7 +507,6 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause, */ restrictinfo = make_restrictinfo((Expr *) clause, is_pushed_down, - valid_everywhere, relids); /* @@ -533,8 +531,7 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause, * allows us to consider z and q equal after their rels are * joined. */ - if (can_be_equijoin) - check_mergejoinable(restrictinfo); + check_mergejoinable(restrictinfo); /* * If the clause was deduced from implied equality, check to @@ -601,18 +598,60 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause, } /* - * If the clause has a mergejoinable operator, and is not an - * outer-join qualification nor bubbled up due to an outer join, then - * the two sides represent equivalent PathKeyItems for path keys: any - * path that is sorted by one side will also be sorted by the other - * (as soon as the two rels are joined, that is). Record the key - * equivalence for future use. (We can skip this for a deduced - * clause, since the keys are already known equivalent in that case.) + * If the clause has a mergejoinable operator, we may be able to + * deduce more things from it under the principle of transitivity. + * + * If it is not an outer-join qualification nor bubbled up due to an outer + * join, then the two sides represent equivalent PathKeyItems for path + * keys: any path that is sorted by one side will also be sorted by the + * other (as soon as the two rels are joined, that is). Pass such clauses + * to add_equijoined_keys. + * + * If it is a left or right outer-join qualification that relates the two + * sides of the outer join (no funny business like leftvar1 = leftvar2 + + * rightvar), we add it to root->left_join_clauses or + * root->right_join_clauses according to which side the nonnullable + * variable appears on. + * + * If it is a full outer-join qualification, we add it to + * root->full_join_clauses. (Ideally we'd discard cases that aren't + * leftvar = rightvar, as we do for left/right joins, but this routine + * doesn't have the info needed to do that; and the current usage of the + * full_join_clauses list doesn't require that, so it's not currently + * worth complicating this routine's API to make it possible.) */ - if (can_be_equijoin && - restrictinfo->mergejoinoperator != InvalidOid && - !isdeduced) - add_equijoined_keys(root, restrictinfo); + if (restrictinfo->mergejoinoperator != InvalidOid) + { + if (maybe_equijoin) + add_equijoined_keys(root, restrictinfo); + else if (maybe_outer_join && restrictinfo->can_join) + { + if (bms_is_subset(restrictinfo->left_relids, + outerjoin_nonnullable) && + !bms_overlap(restrictinfo->right_relids, + outerjoin_nonnullable)) + { + /* we have outervar = innervar */ + root->left_join_clauses = lappend(root->left_join_clauses, + restrictinfo); + } + else if (bms_is_subset(restrictinfo->right_relids, + outerjoin_nonnullable) && + !bms_overlap(restrictinfo->left_relids, + outerjoin_nonnullable)) + { + /* we have innervar = outervar */ + root->right_join_clauses = lappend(root->right_join_clauses, + restrictinfo); + } + else if (bms_equal(outerjoin_nonnullable, qualscope)) + { + /* FULL JOIN (above tests cannot match in this case) */ + root->full_join_clauses = lappend(root->full_join_clauses, + restrictinfo); + } + } + } } /* diff --git a/src/backend/optimizer/plan/planmain.c b/src/backend/optimizer/plan/planmain.c index 788fd2f324..7038a45ac6 100644 --- a/src/backend/optimizer/plan/planmain.c +++ b/src/backend/optimizer/plan/planmain.c @@ -14,7 +14,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/plan/planmain.c,v 1.85 2005/06/10 03:32:23 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/plan/planmain.c,v 1.86 2005/07/02 23:00:41 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -121,6 +121,9 @@ query_planner(PlannerInfo *root, List *tlist, double tuple_fraction, root->join_rel_list = NIL; root->join_rel_hash = NULL; root->equi_key_list = NIL; + root->left_join_clauses = NIL; + root->right_join_clauses = NIL; + root->full_join_clauses = NIL; /* * Construct RelOptInfo nodes for all base relations in query. diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index df8d0556b4..334f8504df 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.189 2005/06/10 02:21:04 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.190 2005/07/02 23:00:41 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -194,7 +194,6 @@ subquery_planner(Query *parse, double tuple_fraction, int saved_planid = PlannerPlanId; PlannerInfo *root; Plan *plan; - bool hasOuterJoins; List *newHaving; List *lst; ListCell *l; @@ -228,12 +227,16 @@ subquery_planner(Query *parse, double tuple_fraction, /* * Detect whether any rangetable entries are RTE_JOIN kind; if not, we * can avoid the expense of doing flatten_join_alias_vars(). Also - * check for outer joins --- if none, we can skip - * reduce_outer_joins(). This must be done after we have done + * check for outer joins --- if none, we can skip reduce_outer_joins() + * and some other processing. This must be done after we have done * pull_up_subqueries, of course. + * + * Note: if reduce_outer_joins manages to eliminate all outer joins, + * root->hasOuterJoins is not reset currently. This is OK since its + * purpose is merely to suppress unnecessary processing in simple cases. */ root->hasJoinRTEs = false; - hasOuterJoins = false; + root->hasOuterJoins = false; foreach(l, parse->rtable) { RangeTblEntry *rte = (RangeTblEntry *) lfirst(l); @@ -243,7 +246,7 @@ subquery_planner(Query *parse, double tuple_fraction, root->hasJoinRTEs = true; if (IS_OUTER_JOIN(rte->jointype)) { - hasOuterJoins = true; + root->hasOuterJoins = true; /* Can quit scanning once we find an outer join */ break; } @@ -347,7 +350,7 @@ subquery_planner(Query *parse, double tuple_fraction, * joins. This step is most easily done after we've done expression * preprocessing. */ - if (hasOuterJoins) + if (root->hasOuterJoins) reduce_outer_joins(root); /* |
