diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 2f7642276cf..25a7056500b 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -15,7 +15,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.305 2005/06/05 22:32:54 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.306 2005/06/09 04:18:58 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1237,6 +1237,7 @@ _copyRestrictInfo(RestrictInfo *from) COPY_SCALAR_FIELD(valid_everywhere); COPY_SCALAR_FIELD(can_join); COPY_BITMAPSET_FIELD(clause_relids); + COPY_BITMAPSET_FIELD(required_relids); COPY_BITMAPSET_FIELD(left_relids); COPY_BITMAPSET_FIELD(right_relids); COPY_NODE_FIELD(orclause); @@ -1262,20 +1263,6 @@ _copyRestrictInfo(RestrictInfo *from) return newnode; } -/* - * _copyJoinInfo - */ -static JoinInfo * -_copyJoinInfo(JoinInfo *from) -{ - JoinInfo *newnode = makeNode(JoinInfo); - - COPY_BITMAPSET_FIELD(unjoined_relids); - COPY_NODE_FIELD(jinfo_restrictinfo); - - return newnode; -} - /* * _copyInClauseInfo */ @@ -2857,9 +2844,6 @@ copyObject(void *from) case T_RestrictInfo: retval = _copyRestrictInfo(from); break; - case T_JoinInfo: - retval = _copyJoinInfo(from); - break; case T_InClauseInfo: retval = _copyInClauseInfo(from); break; diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index a1d951112c8..e625ca7f32c 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -18,7 +18,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.242 2005/06/05 22:32:54 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.243 2005/06/09 04:18:58 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -594,6 +594,7 @@ _equalRestrictInfo(RestrictInfo *a, RestrictInfo *b) COMPARE_NODE_FIELD(clause); COMPARE_SCALAR_FIELD(is_pushed_down); COMPARE_SCALAR_FIELD(valid_everywhere); + COMPARE_BITMAPSET_FIELD(required_relids); /* * We ignore all the remaining fields, since they may not be set yet, @@ -603,15 +604,6 @@ _equalRestrictInfo(RestrictInfo *a, RestrictInfo *b) return true; } -static bool -_equalJoinInfo(JoinInfo *a, JoinInfo *b) -{ - COMPARE_BITMAPSET_FIELD(unjoined_relids); - COMPARE_NODE_FIELD(jinfo_restrictinfo); - - return true; -} - static bool _equalInClauseInfo(InClauseInfo *a, InClauseInfo *b) { @@ -1915,9 +1907,6 @@ equal(void *a, void *b) case T_RestrictInfo: retval = _equalRestrictInfo(a, b); break; - case T_JoinInfo: - retval = _equalJoinInfo(a, b); - break; case T_InClauseInfo: retval = _equalInClauseInfo(a, b); break; diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index 8310894e0c2..2be5e1d98f6 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.254 2005/06/06 04:13:35 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.255 2005/06/09 04:18:58 tgl Exp $ * * NOTES * Every node type that can appear in stored rules' parsetrees *must* @@ -1227,6 +1227,7 @@ _outRestrictInfo(StringInfo str, RestrictInfo *node) WRITE_BOOL_FIELD(valid_everywhere); WRITE_BOOL_FIELD(can_join); WRITE_BITMAPSET_FIELD(clause_relids); + WRITE_BITMAPSET_FIELD(required_relids); WRITE_BITMAPSET_FIELD(left_relids); WRITE_BITMAPSET_FIELD(right_relids); WRITE_NODE_FIELD(orclause); @@ -1238,15 +1239,6 @@ _outRestrictInfo(StringInfo str, RestrictInfo *node) WRITE_OID_FIELD(hashjoinoperator); } -static void -_outJoinInfo(StringInfo str, JoinInfo *node) -{ - WRITE_NODE_TYPE("JOININFO"); - - WRITE_BITMAPSET_FIELD(unjoined_relids); - WRITE_NODE_FIELD(jinfo_restrictinfo); -} - static void _outInnerIndexscanInfo(StringInfo str, InnerIndexscanInfo *node) { @@ -1989,9 +1981,6 @@ _outNode(StringInfo str, void *obj) case T_RestrictInfo: _outRestrictInfo(str, obj); break; - case T_JoinInfo: - _outJoinInfo(str, obj); - break; case T_InnerIndexscanInfo: _outInnerIndexscanInfo(str, obj); break; diff --git a/src/backend/optimizer/README b/src/backend/optimizer/README index 3c2fd32d520..b19f6118ff1 100644 --- a/src/backend/optimizer/README +++ b/src/backend/optimizer/README @@ -75,11 +75,10 @@ way. All the Paths made for a given relation are placed in its RelOptInfo.pathlist. (Actually, we discard Paths that are obviously inferior alternatives before they ever get into the pathlist --- what ends up in the pathlist is the cheapest way of generating each potentially -useful sort ordering of the relation.) Also create RelOptInfo.joininfo -nodes that list all the join clauses that involve this relation. For -example, the WHERE clause "tab1.col1 = tab2.col1" generates a JoinInfo -for tab1 listing tab2 as an unjoined relation, and also one for tab2 -showing tab1 as an unjoined relation. +useful sort ordering of the relation.) Also create a RelOptInfo.joininfo +list including all the join clauses that involve this relation. For +example, the WHERE clause "tab1.col1 = tab2.col1" generates entries in +both tab1 and tab2's joininfo lists. If we have only a single base relation in the query, we are done. Otherwise we have to figure out how to join the base relations into a @@ -252,7 +251,6 @@ RelOptInfo - a relation or joined relations RestrictInfo - WHERE clauses, like "x = 3" or "y = z" (note the same structure is used for restriction and join clauses) - JoinInfo - join clauses associated with a particular pair of relations Path - every way to generate a RelOptInfo(sequential,index,joins) SeqScan - a plain Path node with pathtype = T_SeqScan diff --git a/src/backend/optimizer/geqo/geqo_eval.c b/src/backend/optimizer/geqo/geqo_eval.c index 5d31ac738e7..d1bb3059fc0 100644 --- a/src/backend/optimizer/geqo/geqo_eval.c +++ b/src/backend/optimizer/geqo/geqo_eval.c @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_eval.c,v 1.75 2005/06/08 23:02:04 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_eval.c,v 1.76 2005/06/09 04:18:59 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -26,6 +26,7 @@ #include #include "optimizer/geqo.h" +#include "optimizer/joininfo.h" #include "optimizer/pathnode.h" #include "optimizer/paths.h" #include "utils/memutils.h" @@ -261,13 +262,8 @@ desirable_join(PlannerInfo *root, /* * Join if there is an applicable join clause. */ - foreach(l, outer_rel->joininfo) - { - JoinInfo *joininfo = (JoinInfo *) lfirst(l); - - if (bms_is_subset(joininfo->unjoined_relids, inner_rel->relids)) - return true; - } + if (have_relevant_joinclause(outer_rel, inner_rel)) + return true; /* * Join if the rels are members of the same IN sub-select. This is diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c index f17d1af5a63..4b09f03e6e7 100644 --- a/src/backend/optimizer/path/allpaths.c +++ b/src/backend/optimizer/path/allpaths.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.132 2005/06/06 04:13:35 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.133 2005/06/09 04:18:59 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1048,14 +1048,10 @@ debug_print_rel(PlannerInfo *root, RelOptInfo *rel) printf("\n"); } - foreach(l, rel->joininfo) + if (rel->joininfo) { - JoinInfo *j = (JoinInfo *) lfirst(l); - - printf("\tjoininfo ("); - print_relids(j->unjoined_relids); - printf("): "); - print_restrictclauses(root, j->jinfo_restrictinfo); + printf("\tjoininfo: "); + print_restrictclauses(root, rel->joininfo); printf("\n"); } diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c index 0d5a4e99b36..1b488d191e8 100644 --- a/src/backend/optimizer/path/indxpath.c +++ b/src/backend/optimizer/path/indxpath.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.181 2005/06/05 22:32:55 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.182 2005/06/09 04:18:59 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -71,8 +71,6 @@ static Oid indexable_operator(Expr *clause, Oid opclass, static bool pred_test_recurse(Node *clause, Node *predicate); static bool pred_test_simple_clause(Expr *predicate, Node *clause); static Relids indexable_outerrelids(RelOptInfo *rel); -static bool list_matches_any_index(List *clauses, RelOptInfo *rel, - Relids outer_relids); static bool matches_any_index(RestrictInfo *rinfo, RelOptInfo *rel, Relids outer_relids); static List *find_clauses_for_join(PlannerInfo *root, RelOptInfo *rel, @@ -908,7 +906,7 @@ pred_test(List *predicate_list, List *restrictinfo_list) * classes over equi-joined attributes (i.e., if it recognized that a * qualification such as "where a.b=c.d and a.b=5" could make use of * an index on c.d), then we could use that equivalence class info - * here with joininfo_list to do more complete tests for the usability + * here with joininfo lists to do more complete tests for the usability * of a partial index. For now, the test only uses restriction * clauses (those in restrictinfo_list). --Nels, Dec '92 * @@ -1550,84 +1548,30 @@ indexable_outerrelids(RelOptInfo *rel) Relids outer_relids = NULL; ListCell *l; + /* + * Examine each joinclause in the joininfo list to see if it matches any + * key of any index. If so, add the clause's other rels to the result. + * (Note: we consider only actual participants, not extraneous rels + * possibly mentioned in required_relids.) + */ foreach(l, rel->joininfo) { - JoinInfo *joininfo = (JoinInfo *) lfirst(l); + RestrictInfo *joininfo = (RestrictInfo *) lfirst(l); + Relids other_rels; - /* - * Examine each joinclause in the JoinInfo node's list to see if - * it matches any key of any index. If so, add the JoinInfo's - * otherrels to the result. We can skip examining other - * joinclauses in the same list as soon as we find a match, since - * by definition they all have the same otherrels. - */ - if (list_matches_any_index(joininfo->jinfo_restrictinfo, - rel, - joininfo->unjoined_relids)) - outer_relids = bms_add_members(outer_relids, - joininfo->unjoined_relids); + other_rels = bms_difference(joininfo->clause_relids, rel->relids); + if (matches_any_index(joininfo, rel, other_rels)) + outer_relids = bms_join(outer_relids, other_rels); + else + bms_free(other_rels); } return outer_relids; } -/* - * list_matches_any_index - * Workhorse for indexable_outerrelids: given a list of RestrictInfos, - * see if any of them match any index of the given rel. - * - * We define it like this so that we can recurse into OR subclauses. - */ -static bool -list_matches_any_index(List *clauses, RelOptInfo *rel, Relids outer_relids) -{ - ListCell *l; - - foreach(l, clauses) - { - RestrictInfo *rinfo = (RestrictInfo *) lfirst(l); - ListCell *j; - - Assert(IsA(rinfo, RestrictInfo)); - - /* RestrictInfos that aren't ORs are easy */ - if (!restriction_is_or_clause(rinfo)) - { - if (matches_any_index(rinfo, rel, outer_relids)) - return true; - continue; - } - - foreach(j, ((BoolExpr *) rinfo->orclause)->args) - { - Node *orarg = (Node *) lfirst(j); - - /* OR arguments should be ANDs or sub-RestrictInfos */ - if (and_clause(orarg)) - { - List *andargs = ((BoolExpr *) orarg)->args; - - /* Recurse to examine AND items and sub-ORs */ - if (list_matches_any_index(andargs, rel, outer_relids)) - return true; - } - else - { - Assert(IsA(orarg, RestrictInfo)); - Assert(!restriction_is_or_clause((RestrictInfo *) orarg)); - if (matches_any_index((RestrictInfo *) orarg, rel, - outer_relids)) - return true; - } - } - } - - return false; -} - /* * matches_any_index - * Workhorse for indexable_outerrelids: see if a simple joinclause can be + * Workhorse for indexable_outerrelids: see if a joinclause can be * matched to any index of the given rel. */ static bool @@ -1635,6 +1579,42 @@ matches_any_index(RestrictInfo *rinfo, RelOptInfo *rel, Relids outer_relids) { ListCell *l; + Assert(IsA(rinfo, RestrictInfo)); + + if (restriction_is_or_clause(rinfo)) + { + foreach(l, ((BoolExpr *) rinfo->orclause)->args) + { + Node *orarg = (Node *) lfirst(l); + + /* OR arguments should be ANDs or sub-RestrictInfos */ + if (and_clause(orarg)) + { + ListCell *j; + + /* Recurse to examine AND items and sub-ORs */ + foreach(j, ((BoolExpr *) orarg)->args) + { + RestrictInfo *arinfo = (RestrictInfo *) lfirst(j); + + if (matches_any_index(arinfo, rel, outer_relids)) + return true; + } + } + else + { + /* Recurse to examine simple clause */ + Assert(IsA(orarg, RestrictInfo)); + Assert(!restriction_is_or_clause((RestrictInfo *) orarg)); + if (matches_any_index((RestrictInfo *) orarg, rel, + outer_relids)) + return true; + } + } + + return false; + } + /* Normal case for a simple restriction clause */ foreach(l, rel->indexlist) { @@ -1833,7 +1813,7 @@ find_clauses_for_join(PlannerInfo *root, RelOptInfo *rel, { List *clause_list = NIL; bool jfound = false; - int numsources; + Relids join_relids; ListCell *l; /* @@ -1854,46 +1834,33 @@ find_clauses_for_join(PlannerInfo *root, RelOptInfo *rel, clause_list = lappend(clause_list, rinfo); } - /* found anything in base restrict list? */ - numsources = (clause_list != NIL) ? 1 : 0; - /* Look for joinclauses that are usable with given outer_relids */ + join_relids = bms_union(rel->relids, outer_relids); + foreach(l, rel->joininfo) { - JoinInfo *joininfo = (JoinInfo *) lfirst(l); - bool jfoundhere = false; - ListCell *j; + RestrictInfo *rinfo = (RestrictInfo *) lfirst(l); - if (!bms_is_subset(joininfo->unjoined_relids, outer_relids)) + /* Can't use pushed-down clauses in outer join */ + if (isouterjoin && rinfo->is_pushed_down) + continue; + if (!bms_is_subset(rinfo->required_relids, join_relids)) continue; - foreach(j, joininfo->jinfo_restrictinfo) - { - RestrictInfo *rinfo = (RestrictInfo *) lfirst(j); - - /* Can't use pushed-down clauses in outer join */ - if (isouterjoin && rinfo->is_pushed_down) - continue; - - clause_list = lappend(clause_list, rinfo); - if (!jfoundhere) - { - jfoundhere = true; - jfound = true; - numsources++; - } - } + clause_list = lappend(clause_list, rinfo); + jfound = true; } + bms_free(join_relids); + /* if no join clause was matched then forget it, per comments above */ if (!jfound) return NIL; /* - * If we found clauses in more than one list, we may now have - * clauses that are known redundant. Get rid of 'em. + * We may now have clauses that are known redundant. Get rid of 'em. */ - if (numsources > 1) + if (list_length(clause_list) > 1) { clause_list = remove_redundant_join_clauses(root, clause_list, @@ -2304,7 +2271,8 @@ expand_indexqual_conditions(IndexOptInfo *index, List *clausegroups) { resultquals = lappend(resultquals, make_restrictinfo(boolqual, - true, true)); + true, true, + NULL)); continue; } } @@ -2553,7 +2521,7 @@ prefix_quals(Node *leftop, Oid opclass, elog(ERROR, "no = operator for opclass %u", opclass); expr = make_opclause(oproid, BOOLOID, false, (Expr *) leftop, (Expr *) prefix_const); - result = list_make1(make_restrictinfo(expr, true, true)); + result = list_make1(make_restrictinfo(expr, true, true, NULL)); return result; } @@ -2568,7 +2536,7 @@ prefix_quals(Node *leftop, Oid opclass, elog(ERROR, "no >= operator for opclass %u", opclass); expr = make_opclause(oproid, BOOLOID, false, (Expr *) leftop, (Expr *) prefix_const); - result = list_make1(make_restrictinfo(expr, true, true)); + result = list_make1(make_restrictinfo(expr, true, true, NULL)); /*------- * If we can create a string larger than the prefix, we can say @@ -2584,7 +2552,7 @@ prefix_quals(Node *leftop, Oid opclass, elog(ERROR, "no < operator for opclass %u", opclass); expr = make_opclause(oproid, BOOLOID, false, (Expr *) leftop, (Expr *) greaterstr); - result = lappend(result, make_restrictinfo(expr, true, true)); + result = lappend(result, make_restrictinfo(expr, true, true, NULL)); } return result; @@ -2655,7 +2623,7 @@ network_prefix_quals(Node *leftop, Oid expr_op, Oid opclass, Datum rightop) (Expr *) leftop, (Expr *) makeConst(datatype, -1, opr1right, false, false)); - result = list_make1(make_restrictinfo(expr, true, true)); + result = list_make1(make_restrictinfo(expr, true, true, NULL)); /* create clause "key <= network_scan_last( rightop )" */ @@ -2670,7 +2638,7 @@ network_prefix_quals(Node *leftop, Oid expr_op, Oid opclass, Datum rightop) (Expr *) leftop, (Expr *) makeConst(datatype, -1, opr2right, false, false)); - result = lappend(result, make_restrictinfo(expr, true, true)); + result = lappend(result, make_restrictinfo(expr, true, true, NULL)); return result; } diff --git a/src/backend/optimizer/path/joinrels.c b/src/backend/optimizer/path/joinrels.c index a1681ae994f..f51e492eca1 100644 --- a/src/backend/optimizer/path/joinrels.c +++ b/src/backend/optimizer/path/joinrels.c @@ -8,12 +8,13 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/path/joinrels.c,v 1.73 2005/06/05 22:32:55 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/path/joinrels.c,v 1.74 2005/06/09 04:18:59 tgl Exp $ * *------------------------------------------------------------------------- */ #include "postgres.h" +#include "optimizer/joininfo.h" #include "optimizer/pathnode.h" #include "optimizer/paths.h" @@ -169,30 +170,20 @@ make_rels_by_joins(PlannerInfo *root, int level, List **joinrels) if (!bms_overlap(old_rel->relids, new_rel->relids)) { - ListCell *i; - /* * OK, we can build a rel of the right level from this * pair of rels. Do so if there is at least one * usable join clause. */ - foreach(i, old_rel->joininfo) + if (have_relevant_joinclause(old_rel, new_rel)) { - JoinInfo *joininfo = (JoinInfo *) lfirst(i); + RelOptInfo *jrel; - if (bms_is_subset(joininfo->unjoined_relids, - new_rel->relids)) - { - RelOptInfo *jrel; - - jrel = make_join_rel(root, old_rel, new_rel, - JOIN_INNER); - /* Avoid making duplicate entries ... */ - if (jrel && !list_member_ptr(result_rels, jrel)) - result_rels = lcons(jrel, result_rels); - break; /* need not consider more - * joininfos */ - } + jrel = make_join_rel(root, old_rel, new_rel, + JOIN_INNER); + /* Avoid making duplicate entries ... */ + if (jrel && !list_member_ptr(result_rels, jrel)) + result_rels = lcons(jrel, result_rels); } } } @@ -269,7 +260,7 @@ make_rels_by_joins(PlannerInfo *root, int level, List **joinrels) /* * make_rels_by_clause_joins * Build joins between the given relation 'old_rel' and other relations - * that are mentioned within old_rel's joininfo nodes (i.e., relations + * that are mentioned within old_rel's joininfo list (i.e., relations * that participate in join clauses that 'old_rel' also participates in). * The join rel nodes are returned in a list. * @@ -278,10 +269,7 @@ make_rels_by_joins(PlannerInfo *root, int level, List **joinrels) * rels to be considered for joining * * Currently, this is only used with initial rels in other_rels, but it - * will work for joining to joinrels too, if the caller ensures there is no - * membership overlap between old_rel and the rels in other_rels. (We need - * no extra test for overlap for initial rels, since the is_subset test can - * only succeed when other_rel is not already part of old_rel.) + * will work for joining to joinrels too. */ static List * make_rels_by_clause_joins(PlannerInfo *root, @@ -289,31 +277,20 @@ make_rels_by_clause_joins(PlannerInfo *root, ListCell *other_rels) { List *result = NIL; - ListCell *i, - *j; + ListCell *l; - foreach(i, old_rel->joininfo) + for_each_cell(l, other_rels) { - JoinInfo *joininfo = (JoinInfo *) lfirst(i); - Relids unjoined_relids = joininfo->unjoined_relids; + RelOptInfo *other_rel = (RelOptInfo *) lfirst(l); - for_each_cell(j, other_rels) + if (!bms_overlap(old_rel->relids, other_rel->relids) && + have_relevant_joinclause(old_rel, other_rel)) { - RelOptInfo *other_rel = (RelOptInfo *) lfirst(j); + RelOptInfo *jrel; - if (bms_is_subset(unjoined_relids, other_rel->relids)) - { - RelOptInfo *jrel; - - jrel = make_join_rel(root, old_rel, other_rel, JOIN_INNER); - - /* - * Avoid entering same joinrel into our output list more - * than once. - */ - if (jrel && !list_member_ptr(result, jrel)) - result = lcons(jrel, result); - } + jrel = make_join_rel(root, old_rel, other_rel, JOIN_INNER); + if (jrel) + result = lcons(jrel, result); } } diff --git a/src/backend/optimizer/path/orindxpath.c b/src/backend/optimizer/path/orindxpath.c index 0e2eefc868c..7eadd220b94 100644 --- a/src/backend/optimizer/path/orindxpath.c +++ b/src/backend/optimizer/path/orindxpath.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/path/orindxpath.c,v 1.71 2005/06/05 22:32:55 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/path/orindxpath.c,v 1.72 2005/06/09 04:18:59 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -96,43 +96,37 @@ create_or_index_quals(PlannerInfo *root, RelOptInfo *rel) */ foreach(i, rel->joininfo) { - JoinInfo *joininfo = (JoinInfo *) lfirst(i); - ListCell *j; + RestrictInfo *rinfo = (RestrictInfo *) lfirst(i); - foreach(j, joininfo->jinfo_restrictinfo) + if (restriction_is_or_clause(rinfo) && + rinfo->valid_everywhere) { - RestrictInfo *rinfo = (RestrictInfo *) lfirst(j); + /* + * Use the generate_bitmap_or_paths() machinery to estimate + * the value of each OR clause. We can use regular + * restriction clauses along with the OR clause contents to + * generate indexquals. We pass outer_relids = NULL so that + * sub-clauses that are actually joins will be ignored. + */ + List *orpaths; + ListCell *k; - if (restriction_is_or_clause(rinfo) && - rinfo->valid_everywhere) + orpaths = generate_bitmap_or_paths(root, rel, + list_make1(rinfo), + rel->baserestrictinfo, + false, NULL); + + /* Locate the cheapest OR path */ + foreach(k, orpaths) { - /* - * Use the generate_bitmap_or_paths() machinery to estimate - * the value of each OR clause. We can use regular - * restriction clauses along with the OR clause contents to - * generate indexquals. We pass outer_relids = NULL so that - * sub-clauses that are actually joins will be ignored. - */ - List *orpaths; - ListCell *k; + BitmapOrPath *path = (BitmapOrPath *) lfirst(k); - orpaths = generate_bitmap_or_paths(root, rel, - list_make1(rinfo), - rel->baserestrictinfo, - false, NULL); - - /* Locate the cheapest OR path */ - foreach(k, orpaths) + Assert(IsA(path, BitmapOrPath)); + if (bestpath == NULL || + path->path.total_cost < bestpath->path.total_cost) { - BitmapOrPath *path = (BitmapOrPath *) lfirst(k); - - Assert(IsA(path, BitmapOrPath)); - if (bestpath == NULL || - path->path.total_cost < bestpath->path.total_cost) - { - bestpath = path; - bestrinfo = rinfo; - } + bestpath = path; + bestrinfo = rinfo; } } } diff --git a/src/backend/optimizer/path/pathkeys.c b/src/backend/optimizer/path/pathkeys.c index 2994421e5b7..52075fbf465 100644 --- a/src/backend/optimizer/path/pathkeys.c +++ b/src/backend/optimizer/path/pathkeys.c @@ -11,7 +11,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/path/pathkeys.c,v 1.67 2005/06/05 22:32:55 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/path/pathkeys.c,v 1.68 2005/06/09 04:18:59 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1157,11 +1157,11 @@ make_pathkeys_for_mergeclauses(PlannerInfo *root, /* * pathkeys_useful_for_merging * Count the number of pathkeys that may be useful for mergejoins - * above the given relation (by looking at its joininfo lists). + * above the given relation (by looking at its joininfo list). * * We consider a pathkey potentially useful if it corresponds to the merge * ordering of either side of any joinclause for the rel. This might be - * overoptimistic, since joinclauses that appear in different join lists + * overoptimistic, since joinclauses that require different other relations * might never be usable at the same time, but trying to be exact is likely * to be more trouble than it's worth. */ @@ -1179,31 +1179,22 @@ pathkeys_useful_for_merging(PlannerInfo *root, RelOptInfo *rel, List *pathkeys) foreach(j, rel->joininfo) { - JoinInfo *joininfo = (JoinInfo *) lfirst(j); - ListCell *k; + RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(j); - foreach(k, joininfo->jinfo_restrictinfo) + if (restrictinfo->mergejoinoperator == InvalidOid) + continue; + cache_mergeclause_pathkeys(root, restrictinfo); + + /* + * We can compare canonical pathkey sublists by simple + * pointer equality; see compare_pathkeys. + */ + if (pathkey == restrictinfo->left_pathkey || + pathkey == restrictinfo->right_pathkey) { - RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(k); - - if (restrictinfo->mergejoinoperator == InvalidOid) - continue; - cache_mergeclause_pathkeys(root, restrictinfo); - - /* - * We can compare canonical pathkey sublists by simple - * pointer equality; see compare_pathkeys. - */ - if (pathkey == restrictinfo->left_pathkey || - pathkey == restrictinfo->right_pathkey) - { - matched = true; - break; - } - } - - if (matched) + matched = true; break; + } } /* diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c index c5b02763798..f7066e4906c 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.106 2005/06/05 22:32:55 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/plan/initsplan.c,v 1.107 2005/06/09 04:18:59 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -169,7 +169,7 @@ add_vars_to_targetlist(PlannerInfo *root, List *vars, Relids where_needed) /* * distribute_quals_to_rels * Recursively scan the query's join tree for WHERE and JOIN/ON qual - * clauses, and add these to the appropriate RestrictInfo and JoinInfo + * clauses, and add these to the appropriate restrictinfo and joininfo * lists belonging to base RelOptInfos. Also, base RelOptInfos are marked * with outerjoinset information, to aid in proper positioning of qual * clauses that appear above outer joins. @@ -346,7 +346,7 @@ mark_baserels_for_outer_join(PlannerInfo *root, Relids rels, Relids outerrels) /* * distribute_qual_to_rels - * Add clause information to either the 'RestrictInfo' or 'JoinInfo' field + * Add clause information to either the baserestrictinfo or joininfo list * (depending on whether the clause is a join) of each base relation * mentioned in the clause. A RestrictInfo node is created and added to * the appropriate list for each rel. Also, if the clause uses a @@ -508,7 +508,8 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause, */ restrictinfo = make_restrictinfo((Expr *) clause, is_pushed_down, - valid_everywhere); + valid_everywhere, + relids); /* * Figure out where to attach it. @@ -654,8 +655,8 @@ process_implied_equality(PlannerInfo *root, /* * If the exprs involve a single rel, we need to look at that rel's - * baserestrictinfo list. If multiple rels, any one will have a - * joininfo node for the rest, and we can scan any of 'em. + * baserestrictinfo list. If multiple rels, we can scan the joininfo + * list of any of 'em. */ if (membership == BMS_SINGLETON) { @@ -666,20 +667,14 @@ process_implied_equality(PlannerInfo *root, { Relids other_rels; int first_rel; - JoinInfo *joininfo; /* Copy relids, find and remove one member */ other_rels = bms_copy(relids); first_rel = bms_first_member(other_rels); + bms_free(other_rels); rel1 = find_base_rel(root, first_rel); - - /* use remaining members to find join node */ - joininfo = find_joininfo_node(rel1, other_rels); - - restrictlist = joininfo ? joininfo->jinfo_restrictinfo : NIL; - - bms_free(other_rels); + restrictlist = rel1->joininfo; } /* diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c index e7aee1d52ab..2139ac23f1c 100644 --- a/src/backend/optimizer/prep/prepunion.c +++ b/src/backend/optimizer/prep/prepunion.c @@ -14,7 +14,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/prep/prepunion.c,v 1.122 2005/06/05 22:32:56 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/prep/prepunion.c,v 1.123 2005/06/09 04:18:59 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1023,6 +1023,9 @@ adjust_inherited_attrs_mutator(Node *node, newinfo->clause_relids = adjust_relid_set(oldinfo->clause_relids, context->old_rt_index, context->new_rt_index); + newinfo->required_relids = adjust_relid_set(oldinfo->required_relids, + context->old_rt_index, + context->new_rt_index); newinfo->left_relids = adjust_relid_set(oldinfo->left_relids, context->old_rt_index, context->new_rt_index); diff --git a/src/backend/optimizer/util/joininfo.c b/src/backend/optimizer/util/joininfo.c index b49ead13163..9e66f2db0c6 100644 --- a/src/backend/optimizer/util/joininfo.c +++ b/src/backend/optimizer/util/joininfo.c @@ -1,14 +1,14 @@ /*------------------------------------------------------------------------- * * joininfo.c - * JoinInfo node manipulation routines + * joininfo list manipulation routines * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/util/joininfo.c,v 1.42 2005/06/05 22:32:56 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/util/joininfo.c,v 1.43 2005/06/09 04:19:00 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -19,58 +19,49 @@ /* - * find_joininfo_node - * Find the joininfo node within a relation entry corresponding - * to a join between 'this_rel' and the relations in 'join_relids'. - * If there is no such node, return NULL. - * - * Returns a joininfo node, or NULL. + * have_relevant_joinclause + * Detect whether there is a joinclause that can be used to join + * the two given relations. */ -JoinInfo * -find_joininfo_node(RelOptInfo *this_rel, Relids join_relids) +bool +have_relevant_joinclause(RelOptInfo *rel1, RelOptInfo *rel2) { + bool result = false; + Relids join_relids; + List *joininfo; ListCell *l; - foreach(l, this_rel->joininfo) + join_relids = bms_union(rel1->relids, rel2->relids); + + /* + * We could scan either relation's joininfo list; may as well use the + * shorter one. + */ + if (list_length(rel1->joininfo) <= list_length(rel2->joininfo)) + joininfo = rel1->joininfo; + else + joininfo = rel2->joininfo; + + foreach(l, joininfo) { - JoinInfo *joininfo = (JoinInfo *) lfirst(l); + RestrictInfo *rinfo = (RestrictInfo *) lfirst(l); - if (bms_equal(join_relids, joininfo->unjoined_relids)) - return joininfo; + if (bms_is_subset(rinfo->required_relids, join_relids)) + { + result = true; + break; + } } - return NULL; -} -/* - * make_joininfo_node - * Find the joininfo node within a relation entry corresponding - * to a join between 'this_rel' and the relations in 'join_relids'. - * A new node is created and added to the relation entry's joininfo - * field if the desired one can't be found. - * - * Returns a joininfo node. - */ -JoinInfo * -make_joininfo_node(RelOptInfo *this_rel, Relids join_relids) -{ - JoinInfo *joininfo = find_joininfo_node(this_rel, join_relids); + bms_free(join_relids); - if (joininfo == NULL) - { - joininfo = makeNode(JoinInfo); - joininfo->unjoined_relids = join_relids; - joininfo->jinfo_restrictinfo = NIL; - this_rel->joininfo = lcons(joininfo, this_rel->joininfo); - } - return joininfo; + return result; } /* * add_join_clause_to_rels - * For every relation participating in a join clause, add 'restrictinfo' to - * the appropriate joininfo list (creating a new list and adding it to the - * appropriate rel node if necessary). + * Add 'restrictinfo' to the joininfo list of each relation it requires. * * Note that the same copy of the restrictinfo node is linked to by all the * lists it is in. This allows us to exploit caching of information about @@ -89,32 +80,12 @@ add_join_clause_to_rels(PlannerInfo *root, Relids tmprelids; int cur_relid; - /* For every relid, find the joininfo, and add the proper join entries */ tmprelids = bms_copy(join_relids); while ((cur_relid = bms_first_member(tmprelids)) >= 0) { - Relids unjoined_relids; - JoinInfo *joininfo; + RelOptInfo *rel = find_base_rel(root, cur_relid); - /* Get the relids not equal to the current relid */ - unjoined_relids = bms_copy(join_relids); - unjoined_relids = bms_del_member(unjoined_relids, cur_relid); - Assert(!bms_is_empty(unjoined_relids)); - - /* - * Find or make the joininfo node for this combination of rels, - * and add the restrictinfo node to it. - */ - joininfo = make_joininfo_node(find_base_rel(root, cur_relid), - unjoined_relids); - joininfo->jinfo_restrictinfo = lappend(joininfo->jinfo_restrictinfo, - restrictinfo); - - /* - * Can't bms_free(unjoined_relids) because new joininfo node may - * link to it. We could avoid leaking memory by doing bms_copy() - * in make_joininfo_node, but for now speed seems better. - */ + rel->joininfo = lappend(rel->joininfo, restrictinfo); } bms_free(tmprelids); } @@ -138,34 +109,17 @@ remove_join_clause_from_rels(PlannerInfo *root, Relids tmprelids; int cur_relid; - /* For every relid, find the joininfo */ tmprelids = bms_copy(join_relids); while ((cur_relid = bms_first_member(tmprelids)) >= 0) { - Relids unjoined_relids; - JoinInfo *joininfo; - - /* Get the relids not equal to the current relid */ - unjoined_relids = bms_copy(join_relids); - unjoined_relids = bms_del_member(unjoined_relids, cur_relid); - Assert(!bms_is_empty(unjoined_relids)); - - /* - * Find the joininfo node for this combination of rels; it should - * exist already, if add_join_clause_to_rels was called. - */ - joininfo = find_joininfo_node(find_base_rel(root, cur_relid), - unjoined_relids); - Assert(joininfo); + RelOptInfo *rel = find_base_rel(root, cur_relid); /* * Remove the restrictinfo from the list. Pointer comparison is * sufficient. */ - Assert(list_member_ptr(joininfo->jinfo_restrictinfo, restrictinfo)); - joininfo->jinfo_restrictinfo = list_delete_ptr(joininfo->jinfo_restrictinfo, - restrictinfo); - bms_free(unjoined_relids); + Assert(list_member_ptr(rel->joininfo, restrictinfo)); + rel->joininfo = list_delete_ptr(rel->joininfo, restrictinfo); } bms_free(tmprelids); } diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c index fbaf0de83a8..d66796d5cce 100644 --- a/src/backend/optimizer/util/relnode.c +++ b/src/backend/optimizer/util/relnode.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/util/relnode.c,v 1.69 2005/06/08 23:02:05 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/util/relnode.c,v 1.70 2005/06/09 04:19:00 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -479,8 +479,8 @@ build_joinrel_tlist(PlannerInfo *root, RelOptInfo *joinrel, * * These routines are separate because the restriction list must be * built afresh for each pair of input sub-relations we consider, whereas - * the join lists need only be computed once for any join RelOptInfo. - * The join lists are fully determined by the set of rels making up the + * the join list need only be computed once for any join RelOptInfo. + * The join list is fully determined by the set of rels making up the * joinrel, so we should get the same results (up to ordering) from any * candidate pair of sub-relations. But the restriction list is whatever * is not handled in the sub-relations, so it depends on which @@ -488,7 +488,7 @@ build_joinrel_tlist(PlannerInfo *root, RelOptInfo *joinrel, * * If a join clause from an input relation refers to base rels still not * present in the joinrel, then it is still a join clause for the joinrel; - * we put it into an appropriate JoinInfo list for the joinrel. Otherwise, + * we put it into the joininfo list for the joinrel. Otherwise, * the clause is now a restrict clause for the joined relation, and we * return it to the caller of build_joinrel_restrictlist() to be stored in * join paths made from this pair of sub-relations. (It will not need to @@ -506,7 +506,7 @@ build_joinrel_tlist(PlannerInfo *root, RelOptInfo *joinrel, * * build_joinrel_restrictlist() returns a list of relevant restrictinfos, * whereas build_joinrel_joinlist() stores its results in the joinrel's - * joininfo lists. One or the other must accept each given clause! + * joininfo list. One or the other must accept each given clause! * * NB: Formerly, we made deep(!) copies of each input RestrictInfo to pass * up to the join relation. I believe this is no longer necessary, because @@ -562,29 +562,27 @@ subbuild_joinrel_restrictlist(RelOptInfo *joinrel, List *joininfo_list) { List *restrictlist = NIL; - ListCell *xjoininfo; + ListCell *l; - foreach(xjoininfo, joininfo_list) + foreach(l, joininfo_list) { - JoinInfo *joininfo = (JoinInfo *) lfirst(xjoininfo); + RestrictInfo *rinfo = (RestrictInfo *) lfirst(l); - if (bms_is_subset(joininfo->unjoined_relids, joinrel->relids)) + if (bms_is_subset(rinfo->required_relids, joinrel->relids)) { /* - * Clauses in this JoinInfo list become restriction clauses - * for the joinrel, since they refer to no outside rels. - * - * We must copy the list to avoid disturbing the input relation, - * but we can use a shallow copy. + * This clause becomes a restriction clause for the joinrel, + * since it refers to no outside rels. We don't bother to + * check for duplicates here --- build_joinrel_restrictlist + * will do that. */ - restrictlist = list_concat(restrictlist, - list_copy(joininfo->jinfo_restrictinfo)); + restrictlist = lappend(restrictlist, rinfo); } else { /* - * These clauses are still join clauses at this level, so we - * ignore them in this routine. + * This clause is still a join clause at this level, so we + * ignore it in this routine. */ } } @@ -596,42 +594,33 @@ static void subbuild_joinrel_joinlist(RelOptInfo *joinrel, List *joininfo_list) { - ListCell *xjoininfo; + ListCell *l; - foreach(xjoininfo, joininfo_list) + foreach(l, joininfo_list) { - JoinInfo *joininfo = (JoinInfo *) lfirst(xjoininfo); - Relids new_unjoined_relids; + RestrictInfo *rinfo = (RestrictInfo *) lfirst(l); - new_unjoined_relids = bms_difference(joininfo->unjoined_relids, - joinrel->relids); - if (bms_is_empty(new_unjoined_relids)) + if (bms_is_subset(rinfo->required_relids, joinrel->relids)) { /* - * Clauses in this JoinInfo list become restriction clauses - * for the joinrel, since they refer to no outside rels. So we - * can ignore them in this routine. + * This clause becomes a restriction clause for the joinrel, + * since it refers to no outside rels. So we can ignore it + * in this routine. */ - bms_free(new_unjoined_relids); } else { /* - * These clauses are still join clauses at this level, so find - * or make the appropriate JoinInfo item for the joinrel, and - * add the clauses to it, eliminating duplicates. (Since - * RestrictInfo nodes are normally multiply-linked rather than - * copied, pointer equality should be a sufficient test. If - * two equal() nodes should happen to sneak in, no great harm - * is done --- they'll be detected by redundant-clause testing - * when they reach a restriction list.) + * This clause is still a join clause at this level, so add + * it to the joininfo list for the joinrel, being careful to + * eliminate duplicates. (Since RestrictInfo nodes are normally + * multiply-linked rather than copied, pointer equality should be + * a sufficient test. If two equal() nodes should happen to sneak + * in, no great harm is done --- they'll be detected by + * redundant-clause testing when they reach a restriction list.) */ - JoinInfo *new_joininfo; - - new_joininfo = make_joininfo_node(joinrel, new_unjoined_relids); - new_joininfo->jinfo_restrictinfo = - list_union_ptr(new_joininfo->jinfo_restrictinfo, - joininfo->jinfo_restrictinfo); + if (!list_member_ptr(joinrel->joininfo, rinfo)) + joinrel->joininfo = lappend(joinrel->joininfo, rinfo); } } } diff --git a/src/backend/optimizer/util/restrictinfo.c b/src/backend/optimizer/util/restrictinfo.c index 460ccc9546d..a76f1bb7a2e 100644 --- a/src/backend/optimizer/util/restrictinfo.c +++ b/src/backend/optimizer/util/restrictinfo.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/util/restrictinfo.c,v 1.36 2005/06/05 22:32:56 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/util/restrictinfo.c,v 1.37 2005/06/09 04:19:00 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -24,7 +24,8 @@ static RestrictInfo *make_restrictinfo_internal(Expr *clause, Expr *orclause, bool is_pushed_down, - bool valid_everywhere); + bool valid_everywhere, + Relids required_relids); static Expr *make_sub_restrictinfos(Expr *clause, bool is_pushed_down, bool valid_everywhere); @@ -40,14 +41,16 @@ static RestrictInfo *join_clause_is_redundant(PlannerInfo *root, * Build a RestrictInfo node containing the given subexpression. * * The is_pushed_down and valid_everywhere flags must be supplied by the - * caller. + * caller. required_relids can be NULL, in which case it defaults to the + * actual clause contents (i.e., clause_relids). * * We initialize fields that depend only on the given subexpression, leaving * others that depend on context (or may never be needed at all) to be filled * later. */ RestrictInfo * -make_restrictinfo(Expr *clause, bool is_pushed_down, bool valid_everywhere) +make_restrictinfo(Expr *clause, bool is_pushed_down, bool valid_everywhere, + Relids required_relids) { /* * If it's an OR clause, build a modified copy with RestrictInfos @@ -62,7 +65,8 @@ make_restrictinfo(Expr *clause, bool is_pushed_down, bool valid_everywhere) Assert(!and_clause((Node *) clause)); return make_restrictinfo_internal(clause, NULL, - is_pushed_down, valid_everywhere); + is_pushed_down, valid_everywhere, + required_relids); } /* @@ -133,7 +137,8 @@ make_restrictinfo_from_bitmapqual(Path *bitmapqual, list_make1(make_restrictinfo_internal(make_orclause(withoutris), make_orclause(withris), is_pushed_down, - valid_everywhere)); + valid_everywhere, + NULL)); } else if (IsA(bitmapqual, IndexPath)) { @@ -157,7 +162,8 @@ make_restrictinfo_from_bitmapqual(Path *bitmapqual, */ static RestrictInfo * make_restrictinfo_internal(Expr *clause, Expr *orclause, - bool is_pushed_down, bool valid_everywhere) + bool is_pushed_down, bool valid_everywhere, + Relids required_relids) { RestrictInfo *restrictinfo = makeNode(RestrictInfo); @@ -200,6 +206,12 @@ make_restrictinfo_internal(Expr *clause, Expr *orclause, restrictinfo->clause_relids = pull_varnos((Node *) clause); } + /* required_relids defaults to clause_relids */ + if (required_relids != NULL) + restrictinfo->required_relids = required_relids; + else + restrictinfo->required_relids = restrictinfo->clause_relids; + /* * Fill in all the cacheable fields with "not yet set" markers. None * of these will be computed until/unless needed. Note in particular @@ -254,7 +266,8 @@ make_sub_restrictinfos(Expr *clause, bool is_pushed_down, return (Expr *) make_restrictinfo_internal(clause, make_orclause(orlist), is_pushed_down, - valid_everywhere); + valid_everywhere, + NULL); } else if (and_clause((Node *) clause)) { @@ -272,7 +285,8 @@ make_sub_restrictinfos(Expr *clause, bool is_pushed_down, return (Expr *) make_restrictinfo_internal(clause, NULL, is_pushed_down, - valid_everywhere); + valid_everywhere, + NULL); } /* diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h index 326e929d76f..d9c98321ea3 100644 --- a/src/include/nodes/nodes.h +++ b/src/include/nodes/nodes.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.169 2005/06/05 22:32:57 tgl Exp $ + * $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.170 2005/06/09 04:19:00 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -183,7 +183,6 @@ typedef enum NodeTag T_UniquePath, T_PathKeyItem, T_RestrictInfo, - T_JoinInfo, T_InnerIndexscanInfo, T_InClauseInfo, diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h index 7c702f7105a..ec839d7d3f6 100644 --- a/src/include/nodes/relation.h +++ b/src/include/nodes/relation.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.112 2005/06/08 23:02:05 tgl Exp $ + * $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.113 2005/06/09 04:19:00 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -181,7 +181,7 @@ typedef struct PlannerInfo * and joins that the relation participates in: * * baserestrictinfo - List of RestrictInfo nodes, containing info about - * each qualification clause in which this relation + * each non-join qualification clause in which this relation * participates (only used for base rels) * baserestrictcost - Estimated cost of evaluating the baserestrictinfo * clauses at a single tuple (only used for base rels) @@ -189,8 +189,8 @@ typedef struct PlannerInfo * side of an outer join, the set of all relids * participating in the highest such outer join; else NULL. * Otherwise, unused. - * joininfo - List of JoinInfo nodes, containing info about each join - * clause in which this relation participates + * joininfo - List of RestrictInfo nodes, containing info about each + * join clause in which this relation participates * index_outer_relids - only used for base rels; set of outer relids * that participate in indexable joinclauses for this rel * index_inner_paths - only used for base rels; list of InnerIndexscanInfo @@ -206,7 +206,7 @@ typedef struct PlannerInfo * and should not be processed again at the level of {1 2 3}.) Therefore, * the restrictinfo list in the join case appears in individual JoinPaths * (field joinrestrictinfo), not in the parent relation. But it's OK for - * the RelOptInfo to store the joininfo lists, because those are the same + * the RelOptInfo to store the joininfo list, because that is the same * for a given rel no matter how we form it. * * We store baserestrictcost in the RelOptInfo (for base relations) because @@ -262,7 +262,8 @@ typedef struct RelOptInfo * base rel) */ QualCost baserestrictcost; /* cost of evaluating the above */ Relids outerjoinset; /* set of base relids */ - List *joininfo; /* JoinInfo structures */ + List *joininfo; /* RestrictInfo structures for join clauses + * involving this rel */ /* cached info about inner indexscan paths for relation: */ Relids index_outer_relids; /* other relids in indexable join @@ -645,8 +646,8 @@ typedef struct HashPath * in the baserestrictinfo list of the RelOptInfo for that base rel. * * If a restriction clause references more than one base rel, it will - * appear in the JoinInfo lists of every RelOptInfo that describes a strict - * subset of the base rels mentioned in the clause. The JoinInfo lists are + * appear in the joininfo list of every RelOptInfo that describes a strict + * subset of the base rels mentioned in the clause. The joininfo lists are * used to drive join tree building by selecting plausible join candidates. * The clause cannot actually be applied until we have built a join rel * containing all the base rels it references, however. @@ -676,8 +677,8 @@ typedef struct HashPath * pushed down to a lower level than its original syntactic placement in the * join tree would suggest. If an outer join prevents us from pushing a qual * down to its "natural" semantic level (the level associated with just the - * base rels used in the qual) then the qual will appear in JoinInfo lists - * that reference more than just the base rels it actually uses. By + * base rels used in the qual) then we mark the qual with a "required_relids" + * value including more than just the base rels it actually uses. By * pretending that the qual references all the rels appearing in the outer * join, we prevent it from being evaluated below the outer join's joinrel. * When we do form the outer join's joinrel, we still need to distinguish @@ -685,11 +686,11 @@ typedef struct HashPath * that appeared higher in the tree and were pushed down to the join rel * because they used no other rels. That's what the is_pushed_down flag is * for; it tells us that a qual came from a point above the join of the - * specific set of base rels that it uses (or that the JoinInfo structures - * claim it uses). A clause that originally came from WHERE will *always* - * have its is_pushed_down flag set; a clause that came from an INNER JOIN - * condition, but doesn't use all the rels being joined, will also have - * is_pushed_down set because it will get attached to some lower joinrel. + * set of base rels listed in required_relids. A clause that originally came + * from WHERE will *always* have its is_pushed_down flag set; a clause that + * came from an INNER JOIN condition, but doesn't use all the rels being + * joined, will also have is_pushed_down set because it will get attached to + * some lower joinrel. * * We also store a valid_everywhere flag, which says that the clause is not * affected by any lower-level outer join, and therefore any conditions it @@ -732,9 +733,12 @@ typedef struct RestrictInfo */ bool can_join; - /* The set of relids (varnos) referenced in the clause: */ + /* The set of relids (varnos) actually referenced in the clause: */ Relids clause_relids; + /* The set of relids required to evaluate the clause: */ + Relids required_relids; + /* These fields are set for any binary opclause: */ Relids left_relids; /* relids in left side of clause */ Relids right_relids; /* relids in right side of clause */ @@ -767,27 +771,6 @@ typedef struct RestrictInfo Selectivity right_bucketsize; /* avg bucketsize of right side */ } RestrictInfo; -/* - * Join clause info. - * - * We make a list of these for each RelOptInfo, containing info about - * all the join clauses this RelOptInfo participates in. (For this - * purpose, a "join clause" is a WHERE clause that mentions both vars - * belonging to this relation and vars belonging to relations not yet - * joined to it.) We group these clauses according to the set of - * other base relations (unjoined relations) mentioned in them. - * There is one JoinInfo for each distinct set of unjoined_relids, - * and its jinfo_restrictinfo lists the clause(s) that use that set - * of other relations. - */ - -typedef struct JoinInfo -{ - NodeTag type; - Relids unjoined_relids; /* some rels not yet part of my RelOptInfo */ - List *jinfo_restrictinfo; /* relevant RestrictInfos */ -} JoinInfo; - /* * Inner indexscan info. * diff --git a/src/include/optimizer/joininfo.h b/src/include/optimizer/joininfo.h index b0f0f56fd9b..4e3cd5e031f 100644 --- a/src/include/optimizer/joininfo.h +++ b/src/include/optimizer/joininfo.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/optimizer/joininfo.h,v 1.29 2005/06/05 22:32:58 tgl Exp $ + * $PostgreSQL: pgsql/src/include/optimizer/joininfo.h,v 1.30 2005/06/09 04:19:00 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -17,8 +17,7 @@ #include "nodes/relation.h" -extern JoinInfo *find_joininfo_node(RelOptInfo *this_rel, Relids join_relids); -extern JoinInfo *make_joininfo_node(RelOptInfo *this_rel, Relids join_relids); +extern bool have_relevant_joinclause(RelOptInfo *rel1, RelOptInfo *rel2); extern void add_join_clause_to_rels(PlannerInfo *root, RestrictInfo *restrictinfo, diff --git a/src/include/optimizer/restrictinfo.h b/src/include/optimizer/restrictinfo.h index 4fa6ace6aee..20f51c58204 100644 --- a/src/include/optimizer/restrictinfo.h +++ b/src/include/optimizer/restrictinfo.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/optimizer/restrictinfo.h,v 1.30 2005/06/05 22:32:58 tgl Exp $ + * $PostgreSQL: pgsql/src/include/optimizer/restrictinfo.h,v 1.31 2005/06/09 04:19:00 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -17,8 +17,10 @@ #include "nodes/relation.h" -extern RestrictInfo *make_restrictinfo(Expr *clause, bool is_pushed_down, - bool valid_everywhere); +extern RestrictInfo *make_restrictinfo(Expr *clause, + bool is_pushed_down, + bool valid_everywhere, + Relids required_relids); extern List *make_restrictinfo_from_bitmapqual(Path *bitmapqual, bool is_pushed_down, bool valid_everywhere);