aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/optimizer/path/equivclass.c49
1 files changed, 36 insertions, 13 deletions
diff --git a/src/backend/optimizer/path/equivclass.c b/src/backend/optimizer/path/equivclass.c
index e9bd5eaff5c..b50e9ccdf14 100644
--- a/src/backend/optimizer/path/equivclass.c
+++ b/src/backend/optimizer/path/equivclass.c
@@ -2135,11 +2135,10 @@ add_child_rel_equivalences(PlannerInfo *root,
continue;
/*
- * No point in searching if parent rel not mentioned in eclass; but we
- * can't tell that for sure if parent rel is itself a child.
+ * No point in searching if child's topmost parent rel is not
+ * mentioned in eclass.
*/
- if (parent_rel->reloptkind == RELOPT_BASEREL &&
- !bms_is_subset(parent_rel->relids, cur_ec->ec_relids))
+ if (!bms_is_subset(child_rel->top_parent_relids, cur_ec->ec_relids))
continue;
foreach(lc2, cur_ec->ec_members)
@@ -2149,18 +2148,41 @@ add_child_rel_equivalences(PlannerInfo *root,
if (cur_em->em_is_const)
continue; /* ignore consts here */
- /* Does it reference parent_rel? */
- if (bms_overlap(cur_em->em_relids, parent_rel->relids))
+ /*
+ * We consider only original EC members here, not
+ * already-transformed child members. Otherwise, if some original
+ * member expression references more than one appendrel, we'd get
+ * an O(N^2) explosion of useless derived expressions for
+ * combinations of children.
+ */
+ if (cur_em->em_is_child)
+ continue; /* ignore children here */
+
+ /* Does this member reference child's topmost parent rel? */
+ if (bms_overlap(cur_em->em_relids, child_rel->top_parent_relids))
{
/* Yes, generate transformed child version */
Expr *child_expr;
Relids new_relids;
Relids new_nullable_relids;
- child_expr = (Expr *)
- adjust_appendrel_attrs(root,
- (Node *) cur_em->em_expr,
- 1, &appinfo);
+ if (parent_rel->reloptkind == RELOPT_BASEREL)
+ {
+ /* Simple single-level transformation */
+ child_expr = (Expr *)
+ adjust_appendrel_attrs(root,
+ (Node *) cur_em->em_expr,
+ 1, &appinfo);
+ }
+ else
+ {
+ /* Must do multi-level transformation */
+ child_expr = (Expr *)
+ adjust_appendrel_attrs_multilevel(root,
+ (Node *) cur_em->em_expr,
+ child_rel->relids,
+ child_rel->top_parent_relids);
+ }
/*
* Transform em_relids to match. Note we do *not* do
@@ -2169,7 +2191,7 @@ add_child_rel_equivalences(PlannerInfo *root,
* don't want the child member to be marked as constant.
*/
new_relids = bms_difference(cur_em->em_relids,
- parent_rel->relids);
+ child_rel->top_parent_relids);
new_relids = bms_add_members(new_relids, child_rel->relids);
/*
@@ -2177,10 +2199,11 @@ add_child_rel_equivalences(PlannerInfo *root,
* parent and child relids are singletons.
*/
new_nullable_relids = cur_em->em_nullable_relids;
- if (bms_overlap(new_nullable_relids, parent_rel->relids))
+ if (bms_overlap(new_nullable_relids,
+ child_rel->top_parent_relids))
{
new_nullable_relids = bms_difference(new_nullable_relids,
- parent_rel->relids);
+ child_rel->top_parent_relids);
new_nullable_relids = bms_add_members(new_nullable_relids,
child_rel->relids);
}