diff options
Diffstat (limited to 'src/backend')
-rw-r--r-- | src/backend/optimizer/path/equivclass.c | 38 | ||||
-rw-r--r-- | src/backend/optimizer/path/indxpath.c | 9 | ||||
-rw-r--r-- | src/backend/optimizer/prep/prepunion.c | 23 | ||||
-rw-r--r-- | src/backend/optimizer/util/relnode.c | 59 |
4 files changed, 103 insertions, 26 deletions
diff --git a/src/backend/optimizer/path/equivclass.c b/src/backend/optimizer/path/equivclass.c index b7aff3775ee..e5dd58efe33 100644 --- a/src/backend/optimizer/path/equivclass.c +++ b/src/backend/optimizer/path/equivclass.c @@ -48,7 +48,7 @@ static List *generate_join_implied_equalities_broken(PlannerInfo *root, Relids nominal_join_relids, Relids outer_relids, Relids nominal_inner_relids, - AppendRelInfo *inner_appinfo); + RelOptInfo *inner_rel); static Oid select_equality_operator(EquivalenceClass *ec, Oid lefttype, Oid righttype); static RestrictInfo *create_join_clause(PlannerInfo *root, @@ -1000,22 +1000,18 @@ generate_join_implied_equalities(PlannerInfo *root, Relids inner_relids = inner_rel->relids; Relids nominal_inner_relids; Relids nominal_join_relids; - AppendRelInfo *inner_appinfo; ListCell *lc; /* If inner rel is a child, extra setup work is needed */ if (inner_rel->reloptkind == RELOPT_OTHER_MEMBER_REL) { - /* Lookup parent->child translation data */ - inner_appinfo = find_childrel_appendrelinfo(root, inner_rel); - /* Construct relids for the parent rel */ - nominal_inner_relids = bms_make_singleton(inner_appinfo->parent_relid); + /* Fetch relid set for the topmost parent rel */ + nominal_inner_relids = find_childrel_top_parent(root, inner_rel)->relids; /* ECs will be marked with the parent's relid, not the child's */ nominal_join_relids = bms_union(outer_relids, nominal_inner_relids); } else { - inner_appinfo = NULL; nominal_inner_relids = inner_relids; nominal_join_relids = join_relids; } @@ -1051,7 +1047,7 @@ generate_join_implied_equalities(PlannerInfo *root, nominal_join_relids, outer_relids, nominal_inner_relids, - inner_appinfo); + inner_rel); result = list_concat(result, sublist); } @@ -1244,7 +1240,7 @@ generate_join_implied_equalities_broken(PlannerInfo *root, Relids nominal_join_relids, Relids outer_relids, Relids nominal_inner_relids, - AppendRelInfo *inner_appinfo) + RelOptInfo *inner_rel) { List *result = NIL; ListCell *lc; @@ -1266,10 +1262,16 @@ generate_join_implied_equalities_broken(PlannerInfo *root, * RestrictInfos that are not listed in ec_derives, but there shouldn't be * any duplication, and it's a sufficiently narrow corner case that we * shouldn't sweat too much over it anyway. + * + * Since inner_rel might be an indirect descendant of the baserel + * mentioned in the ec_sources clauses, we have to be prepared to apply + * multiple levels of Var translation. */ - if (inner_appinfo) - result = (List *) adjust_appendrel_attrs(root, (Node *) result, - inner_appinfo); + if (inner_rel->reloptkind == RELOPT_OTHER_MEMBER_REL && + result != NIL) + result = (List *) adjust_appendrel_attrs_multilevel(root, + (Node *) result, + inner_rel); return result; } @@ -2071,14 +2073,14 @@ generate_implied_equalities_for_column(PlannerInfo *root, { List *result = NIL; bool is_child_rel = (rel->reloptkind == RELOPT_OTHER_MEMBER_REL); - Index parent_relid; + Relids parent_relids; ListCell *lc1; - /* If it's a child rel, we'll need to know what its parent is */ + /* If it's a child rel, we'll need to know what its parent(s) are */ if (is_child_rel) - parent_relid = find_childrel_appendrelinfo(root, rel)->parent_relid; + parent_relids = find_childrel_parents(root, rel); else - parent_relid = 0; /* not used, but keep compiler quiet */ + parent_relids = NULL; /* not used, but keep compiler quiet */ foreach(lc1, root->eq_classes) { @@ -2148,10 +2150,10 @@ generate_implied_equalities_for_column(PlannerInfo *root, /* * Also, if this is a child rel, avoid generating a useless join - * to its parent rel. + * to its parent rel(s). */ if (is_child_rel && - bms_is_member(parent_relid, other_em->em_relids)) + bms_overlap(parent_relids, other_em->em_relids)) continue; eq_op = select_equality_operator(cur_ec, diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c index 42dcb111aeb..9c22d31150a 100644 --- a/src/backend/optimizer/path/indxpath.c +++ b/src/backend/optimizer/path/indxpath.c @@ -2586,16 +2586,11 @@ check_partial_indexes(PlannerInfo *root, RelOptInfo *rel) * Add on any equivalence-derivable join clauses. Computing the correct * relid sets for generate_join_implied_equalities is slightly tricky * because the rel could be a child rel rather than a true baserel, and in - * that case we must remove its parent's relid from all_baserels. + * that case we must remove its parents' relid(s) from all_baserels. */ if (rel->reloptkind == RELOPT_OTHER_MEMBER_REL) - { - /* Lookup parent->child translation data */ - AppendRelInfo *appinfo = find_childrel_appendrelinfo(root, rel); - otherrels = bms_difference(root->all_baserels, - bms_make_singleton(appinfo->parent_relid)); - } + find_childrel_parents(root, rel)); else otherrels = bms_difference(root->all_baserels, rel->relids); diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c index 0410fddc546..1cec511e0f0 100644 --- a/src/backend/optimizer/prep/prepunion.c +++ b/src/backend/optimizer/prep/prepunion.c @@ -1979,3 +1979,26 @@ adjust_inherited_tlist(List *tlist, AppendRelInfo *context) return new_tlist; } + +/* + * adjust_appendrel_attrs_multilevel + * Apply Var translations from a toplevel appendrel parent down to a child. + * + * In some cases we need to translate expressions referencing a baserel + * to reference an appendrel child that's multiple levels removed from it. + */ +Node * +adjust_appendrel_attrs_multilevel(PlannerInfo *root, Node *node, + RelOptInfo *child_rel) +{ + AppendRelInfo *appinfo = find_childrel_appendrelinfo(root, child_rel); + RelOptInfo *parent_rel = find_base_rel(root, appinfo->parent_relid); + + /* If parent is also a child, first recurse to apply its translations */ + if (parent_rel->reloptkind == RELOPT_OTHER_MEMBER_REL) + node = adjust_appendrel_attrs_multilevel(root, node, parent_rel); + else + Assert(parent_rel->reloptkind == RELOPT_BASEREL); + /* Now translate for this child */ + return adjust_appendrel_attrs(root, node, appinfo); +} diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c index c938c2700f9..4c76f542b9b 100644 --- a/src/backend/optimizer/util/relnode.c +++ b/src/backend/optimizer/util/relnode.c @@ -713,7 +713,8 @@ build_empty_join_rel(PlannerInfo *root) * Get the AppendRelInfo associated with an appendrel child rel. * * This search could be eliminated by storing a link in child RelOptInfos, - * but for now it doesn't seem performance-critical. + * but for now it doesn't seem performance-critical. (Also, it might be + * difficult to maintain such a link during mutation of the append_rel_list.) */ AppendRelInfo * find_childrel_appendrelinfo(PlannerInfo *root, RelOptInfo *rel) @@ -738,6 +739,62 @@ find_childrel_appendrelinfo(PlannerInfo *root, RelOptInfo *rel) /* + * find_childrel_top_parent + * Fetch the topmost appendrel parent rel of an appendrel child rel. + * + * Since appendrels can be nested, a child could have multiple levels of + * appendrel ancestors. This function locates the topmost ancestor, + * which will be a regular baserel not an otherrel. + */ +RelOptInfo * +find_childrel_top_parent(PlannerInfo *root, RelOptInfo *rel) +{ + do + { + AppendRelInfo *appinfo = find_childrel_appendrelinfo(root, rel); + Index prelid = appinfo->parent_relid; + + /* traverse up to the parent rel, loop if it's also a child rel */ + rel = find_base_rel(root, prelid); + } while (rel->reloptkind == RELOPT_OTHER_MEMBER_REL); + + Assert(rel->reloptkind == RELOPT_BASEREL); + + return rel; +} + + +/* + * find_childrel_parents + * Compute the set of parent relids of an appendrel child rel. + * + * Since appendrels can be nested, a child could have multiple levels of + * appendrel ancestors. This function computes a Relids set of all the + * parent relation IDs. + */ +Relids +find_childrel_parents(PlannerInfo *root, RelOptInfo *rel) +{ + Relids result = NULL; + + do + { + AppendRelInfo *appinfo = find_childrel_appendrelinfo(root, rel); + Index prelid = appinfo->parent_relid; + + result = bms_add_member(result, prelid); + + /* traverse up to the parent rel, loop if it's also a child rel */ + rel = find_base_rel(root, prelid); + } while (rel->reloptkind == RELOPT_OTHER_MEMBER_REL); + + Assert(rel->reloptkind == RELOPT_BASEREL); + + return result; +} + + +/* * get_baserel_parampathinfo * Get the ParamPathInfo for a parameterized path for a base relation, * constructing one if we don't have one already. |