aboutsummaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/optimizer/path/equivclass.c38
-rw-r--r--src/backend/optimizer/path/indxpath.c9
-rw-r--r--src/backend/optimizer/prep/prepunion.c23
-rw-r--r--src/backend/optimizer/util/relnode.c59
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.