diff options
Diffstat (limited to 'src/backend/optimizer')
-rw-r--r-- | src/backend/optimizer/path/equivclass.c | 154 | ||||
-rw-r--r-- | src/backend/optimizer/util/relnode.c | 15 |
2 files changed, 156 insertions, 13 deletions
diff --git a/src/backend/optimizer/path/equivclass.c b/src/backend/optimizer/path/equivclass.c index 688d9b07075..9264d819109 100644 --- a/src/backend/optimizer/path/equivclass.c +++ b/src/backend/optimizer/path/equivclass.c @@ -2103,7 +2103,7 @@ match_eclasses_to_foreign_key_col(PlannerInfo *root, /* * add_child_rel_equivalences - * Search for EC members that reference the parent_rel, and + * Search for EC members that reference the root parent of child_rel, and * add transformed members referencing the child_rel. * * Note that this function won't be called at all unless we have at least some @@ -2111,6 +2111,12 @@ match_eclasses_to_foreign_key_col(PlannerInfo *root, * * parent_rel and child_rel could be derived from appinfo, but since the * caller has already computed them, we might as well just pass them in. + * + * The passed-in AppendRelInfo is not used when the parent_rel is not a + * top-level baserel, since it shows the mapping from the parent_rel but + * we need to translate EC expressions that refer to the top-level parent. + * Using it is faster than using adjust_appendrel_attrs_multilevel(), though, + * so we prefer it when we can. */ void add_child_rel_equivalences(PlannerInfo *root, @@ -2118,8 +2124,12 @@ add_child_rel_equivalences(PlannerInfo *root, RelOptInfo *parent_rel, RelOptInfo *child_rel) { + Relids top_parent_relids = child_rel->top_parent_relids; + Relids child_relids = child_rel->relids; ListCell *lc1; + Assert(IS_SIMPLE_REL(parent_rel)); + foreach(lc1, root->eq_classes) { EquivalenceClass *cur_ec = (EquivalenceClass *) lfirst(lc1); @@ -2137,7 +2147,7 @@ add_child_rel_equivalences(PlannerInfo *root, * No point in searching if child's topmost parent rel is not * mentioned in eclass. */ - if (!bms_is_subset(child_rel->top_parent_relids, cur_ec->ec_relids)) + if (!bms_is_subset(top_parent_relids, cur_ec->ec_relids)) continue; foreach(lc2, cur_ec->ec_members) @@ -2152,13 +2162,14 @@ add_child_rel_equivalences(PlannerInfo *root, * 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. + * combinations of children. (But add_child_join_rel_equivalences + * may add targeted combinations for partitionwise-join purposes.) */ 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)) + if (bms_overlap(cur_em->em_relids, top_parent_relids)) { /* Yes, generate transformed child version */ Expr *child_expr; @@ -2179,8 +2190,8 @@ add_child_rel_equivalences(PlannerInfo *root, child_expr = (Expr *) adjust_appendrel_attrs_multilevel(root, (Node *) cur_em->em_expr, - child_rel->relids, - child_rel->top_parent_relids); + child_relids, + top_parent_relids); } /* @@ -2190,22 +2201,141 @@ 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, - child_rel->top_parent_relids); - new_relids = bms_add_members(new_relids, child_rel->relids); + top_parent_relids); + new_relids = bms_add_members(new_relids, child_relids); /* * And likewise for nullable_relids. Note this code assumes * parent and child relids are singletons. */ new_nullable_relids = cur_em->em_nullable_relids; - if (bms_overlap(new_nullable_relids, - child_rel->top_parent_relids)) + if (bms_overlap(new_nullable_relids, top_parent_relids)) { new_nullable_relids = bms_difference(new_nullable_relids, - child_rel->top_parent_relids); + top_parent_relids); new_nullable_relids = bms_add_members(new_nullable_relids, - child_rel->relids); + child_relids); + } + + (void) add_eq_member(cur_ec, child_expr, + new_relids, new_nullable_relids, + true, cur_em->em_datatype); + } + } + } +} + +/* + * add_child_join_rel_equivalences + * Like add_child_rel_equivalences(), but for joinrels + * + * Here we find the ECs relevant to the top parent joinrel and add transformed + * member expressions that refer to this child joinrel. + * + * Note that this function won't be called at all unless we have at least some + * reason to believe that the EC members it generates will be useful. + */ +void +add_child_join_rel_equivalences(PlannerInfo *root, + int nappinfos, AppendRelInfo **appinfos, + RelOptInfo *parent_joinrel, + RelOptInfo *child_joinrel) +{ + Relids top_parent_relids = child_joinrel->top_parent_relids; + Relids child_relids = child_joinrel->relids; + ListCell *lc1; + + Assert(IS_JOIN_REL(child_joinrel) && IS_JOIN_REL(parent_joinrel)); + + foreach(lc1, root->eq_classes) + { + EquivalenceClass *cur_ec = (EquivalenceClass *) lfirst(lc1); + ListCell *lc2; + + /* + * If this EC contains a volatile expression, then generating child + * EMs would be downright dangerous, so skip it. We rely on a + * volatile EC having only one EM. + */ + if (cur_ec->ec_has_volatile) + continue; + + /* + * No point in searching if child's topmost parent rel is not + * mentioned in eclass. + */ + if (!bms_overlap(top_parent_relids, cur_ec->ec_relids)) + continue; + + foreach(lc2, cur_ec->ec_members) + { + EquivalenceMember *cur_em = (EquivalenceMember *) lfirst(lc2); + + if (cur_em->em_is_const) + continue; /* ignore consts here */ + + /* + * We consider only original EC members here, not + * already-transformed child members. + */ + if (cur_em->em_is_child) + continue; /* ignore children here */ + + /* + * We may ignore expressions that reference a single baserel, + * because add_child_rel_equivalences should have handled them. + */ + if (bms_membership(cur_em->em_relids) != BMS_MULTIPLE) + continue; + + /* Does this member reference child's topmost parent rel? */ + if (bms_overlap(cur_em->em_relids, top_parent_relids)) + { + /* Yes, generate transformed child version */ + Expr *child_expr; + Relids new_relids; + Relids new_nullable_relids; + + if (parent_joinrel->reloptkind == RELOPT_JOINREL) + { + /* Simple single-level transformation */ + child_expr = (Expr *) + adjust_appendrel_attrs(root, + (Node *) cur_em->em_expr, + nappinfos, appinfos); } + else + { + /* Must do multi-level transformation */ + Assert(parent_joinrel->reloptkind == RELOPT_OTHER_JOINREL); + child_expr = (Expr *) + adjust_appendrel_attrs_multilevel(root, + (Node *) cur_em->em_expr, + child_relids, + top_parent_relids); + } + + /* + * Transform em_relids to match. Note we do *not* do + * pull_varnos(child_expr) here, as for example the + * transformation might have substituted a constant, but we + * don't want the child member to be marked as constant. + */ + new_relids = bms_difference(cur_em->em_relids, + top_parent_relids); + new_relids = bms_add_members(new_relids, child_relids); + + /* + * For nullable_relids, we must selectively replace parent + * nullable relids with child ones. + */ + new_nullable_relids = cur_em->em_nullable_relids; + if (bms_overlap(new_nullable_relids, top_parent_relids)) + new_nullable_relids = + adjust_child_relids_multilevel(root, + new_nullable_relids, + child_relids, + top_parent_relids); (void) add_eq_member(cur_ec, child_expr, new_relids, new_nullable_relids, diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c index 6054bd2b535..cefa4105edd 100644 --- a/src/backend/optimizer/util/relnode.c +++ b/src/backend/optimizer/util/relnode.c @@ -837,6 +837,7 @@ build_child_join_rel(PlannerInfo *root, RelOptInfo *outer_rel, /* Compute information relevant to foreign relations. */ set_foreign_rel_properties(joinrel, outer_rel, inner_rel); + /* Compute information needed for mapping Vars to the child rel */ appinfos = find_appinfos_by_relids(root, joinrel->relids, &nappinfos); /* Set up reltarget struct */ @@ -848,7 +849,6 @@ build_child_join_rel(PlannerInfo *root, RelOptInfo *outer_rel, (Node *) parent_joinrel->joininfo, nappinfos, appinfos); - pfree(appinfos); /* * Lateral relids referred in child join will be same as that referred in @@ -883,6 +883,19 @@ build_child_join_rel(PlannerInfo *root, RelOptInfo *outer_rel, /* Add the relation to the PlannerInfo. */ add_join_rel(root, joinrel); + /* + * We might need EquivalenceClass members corresponding to the child join, + * so that we can represent sort pathkeys for it. As with children of + * baserels, we shouldn't need this unless there are relevant eclass joins + * (implying that a merge join might be possible) or pathkeys to sort by. + */ + if (joinrel->has_eclass_joins || has_useful_pathkeys(root, parent_joinrel)) + add_child_join_rel_equivalences(root, + nappinfos, appinfos, + parent_joinrel, joinrel); + + pfree(appinfos); + return joinrel; } |