diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c index 7444622a527..d6a0dd524c4 100644 --- a/contrib/postgres_fdw/postgres_fdw.c +++ b/contrib/postgres_fdw/postgres_fdw.c @@ -7829,35 +7829,12 @@ EquivalenceMember * find_em_for_rel(PlannerInfo *root, EquivalenceClass *ec, RelOptInfo *rel) { PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) rel->fdw_private; - Relids top_parent_rel_relids; EquivalenceChildMemberIterator it; EquivalenceMember *em; - /* - * First, we translate the given Relids to their top-level parents. This - * is required because an EquivalenceClass contains only parent - * EquivalenceMembers, and we have to translate top-level ones to get - * child members. We can skip such translations if we now see top-level - * ones, i.e., when top_parent_rel is NULL. See the - * find_relids_top_parents()'s definition for more details. - */ - top_parent_rel_relids = find_relids_top_parents(root, rel->relids); - - /* - * If we need to see child EquivalenceMembers, we access them via - * EquivalenceChildMemberIterator during the iteration. - */ - setup_eclass_child_member_iterator(&it, ec); + setup_eclass_child_member_iterator(&it, root, ec, rel->relids); while ((em = eclass_child_member_iterator_next(&it))) { - /* - * If child EquivalenceMembers may match the request, we add and - * iterate over them by calling iterate_child_rel_equivalences(). - */ - if (top_parent_rel_relids != NULL && !em->em_is_child && - bms_is_subset(em->em_relids, top_parent_rel_relids)) - iterate_child_rel_equivalences(&it, root, ec, em, rel->relids); - /* * Note we require !bms_is_empty, else we'd accept constant * expressions which are not suitable for the purpose. diff --git a/src/backend/optimizer/path/equivclass.c b/src/backend/optimizer/path/equivclass.c index 0395cee9a7c..173449080f0 100644 --- a/src/backend/optimizer/path/equivclass.c +++ b/src/backend/optimizer/path/equivclass.c @@ -79,7 +79,6 @@ static JoinDomain *find_join_domain(PlannerInfo *root, Relids relids); static void add_transformed_child_version(EquivalenceChildMemberIterator *it, PlannerInfo *root, EquivalenceClass *ec, - EquivalenceMember *parent_em, RelOptInfo *child_rel); static Bitmapset *get_eclass_indexes_for_relids(PlannerInfo *root, Relids relids); @@ -551,8 +550,7 @@ make_eq_member(EquivalenceClass *ec, Expr *expr, Relids relids, em->em_datatype = datatype; em->em_jdomain = jdomain; em->em_parent = parent; - em->em_child_relids = NULL; - em->em_child_joinrel_relids = NULL; + em->em_ec = ec; if (bms_is_empty(relids)) { @@ -581,9 +579,10 @@ make_eq_member(EquivalenceClass *ec, Expr *expr, Relids relids, * add_parent_eq_member - build a new parent EquivalenceMember and add it to an EC * * Note: We don't have a function to add a child member like - * add_child_eq_member() because how to do it depends on the relations they are - * translated from. See add_child_rel_equivalences() and - * add_child_join_rel_equivalences() to see how to add child members. + * add_child_eq_member() because how to do it depends on the relations they + * are translated from. See add_child_rel_equivalences(), + * add_child_join_rel_equivalences() and add_setop_child_rel_equivalences() + * to see how to add child members. */ static EquivalenceMember * add_parent_eq_member(EquivalenceClass *ec, Expr *expr, Relids relids, @@ -805,17 +804,6 @@ get_eclass_for_sort_expr(PlannerInfo *root, EquivalenceMember *newem; ListCell *lc1; MemoryContext oldcontext; - Relids top_parent_rel; - - /* - * First, we translate the given Relids to their top-level parents. This - * is required because an EquivalenceClass contains only parent - * EquivalenceMembers, and we have to translate top-level ones to get - * child members. We can skip such translations if we now see top-level - * ones, i.e., when top_parent_rel is NULL. See the - * find_relids_top_parents()'s definition for more details. - */ - top_parent_rel = find_relids_top_parents(root, rel); /* * Ensure the expression exposes the correct type and collation. @@ -850,28 +838,15 @@ get_eclass_for_sort_expr(PlannerInfo *root, if (!equal(opfamilies, cur_ec->ec_opfamilies)) continue; - /* - * If we need to see child EquivalenceMembers, we access them via - * EquivalenceChildMemberIterator during the iteration. - */ - setup_eclass_child_member_iterator(&it, cur_ec); + setup_eclass_child_member_iterator(&it, root, cur_ec, rel); while ((cur_em = eclass_child_member_iterator_next(&it)) != NULL) { /* - * If child EquivalenceMembers may match the request, we add and - * iterate over them by calling iterate_child_rel_equivalences(). - */ - if (top_parent_rel != NULL && !cur_em->em_is_child && - bms_equal(cur_em->em_relids, top_parent_rel)) - iterate_child_rel_equivalences(&it, root, cur_ec, cur_em, rel); - - /* - * Ignore child members unless they match the request. If this - * EquivalenceMember is a child, i.e., translated above, it should - * match the request. We cannot assert this if a request is - * bms_is_subset(). + * Ignore child members unless they match the request. */ - Assert(!cur_em->em_is_child || bms_equal(cur_em->em_relids, rel)); + if (cur_em->em_is_child && + !bms_equal(cur_em->em_relids, rel)) + continue; /* * Match constants only within the same JoinDomain (see @@ -996,29 +971,14 @@ find_ec_member_matching_expr(PlannerInfo *root, EquivalenceClass *ec, Expr *expr, Relids relids) { - Relids top_parent_relids; EquivalenceChildMemberIterator it; EquivalenceMember *em; - /* - * First, we translate the given Relids to their top-level parents. This - * is required because an EquivalenceClass contains only parent - * EquivalenceMembers, and we have to translate top-level ones to get - * child members. We can skip such translations if we now see top-level - * ones, i.e., when top_parent_rel is NULL. See the - * find_relids_top_parents()'s definition for more details. - */ - top_parent_relids = find_relids_top_parents(root, relids); - /* We ignore binary-compatible relabeling on both ends */ while (expr && IsA(expr, RelabelType)) expr = ((RelabelType *) expr)->arg; - /* - * If we need to see child EquivalenceMembers, we access them via - * EquivalenceChildMemberIterator during the iteration. - */ - setup_eclass_child_member_iterator(&it, ec); + setup_eclass_child_member_iterator(&it, root, ec, relids); while ((em = eclass_child_member_iterator_next(&it)) != NULL) { Expr *emexpr; @@ -1030,14 +990,6 @@ find_ec_member_matching_expr(PlannerInfo *root, EquivalenceClass *ec, if (em->em_is_const) continue; - /* - * If child EquivalenceMembers may match the request, we add and - * iterate over them by calling iterate_child_rel_equivalences(). - */ - if (top_parent_relids != NULL && !em->em_is_child && - bms_is_subset(em->em_relids, top_parent_relids)) - iterate_child_rel_equivalences(&it, root, ec, em, relids); - /* * Ignore child members unless they belong to the requested rel. */ @@ -1098,7 +1050,6 @@ find_computable_ec_member(PlannerInfo *root, bool require_parallel_safe) { List *exprvars; - Relids top_parent_relids; EquivalenceChildMemberIterator it; EquivalenceMember *em; @@ -1113,21 +1064,7 @@ find_computable_ec_member(PlannerInfo *root, PVC_INCLUDE_WINDOWFUNCS | PVC_INCLUDE_PLACEHOLDERS); - /* - * First, we translate the given Relids to their top-level parents. This - * is required because an EquivalenceClass contains only parent - * EquivalenceMembers, and we have to translate top-level ones to get - * child members. We can skip such translations if we now see top-level - * ones, i.e., when top_parent_rel is NULL. See the - * find_relids_top_parents()'s definition for more details. - */ - top_parent_relids = find_relids_top_parents(root, relids); - - /* - * If we need to see child EquivalenceMembers, we access them via - * EquivalenceChildMemberIterator during the iteration. - */ - setup_eclass_child_member_iterator(&it, ec); + setup_eclass_child_member_iterator(&it, root, ec, relids); while ((em = eclass_child_member_iterator_next(&it)) != NULL) { List *emvars; @@ -1140,14 +1077,6 @@ find_computable_ec_member(PlannerInfo *root, if (em->em_is_const) continue; - /* - * If child EquivalenceMembers may match the request, we add and - * iterate over them by calling iterate_child_rel_equivalences(). - */ - if (top_parent_relids != NULL && !em->em_is_child && - bms_is_subset(em->em_relids, top_parent_relids)) - iterate_child_rel_equivalences(&it, root, ec, em, relids); - /* * Ignore child members unless they belong to the requested rel. */ @@ -1848,20 +1777,9 @@ generate_join_implied_equalities_normal(PlannerInfo *root, List *new_members = NIL; List *outer_members = NIL; List *inner_members = NIL; - Relids top_parent_join_relids; EquivalenceChildMemberIterator it; EquivalenceMember *cur_em; - /* - * First, we translate the given Relids to their top-level parents. This - * is required because an EquivalenceClass contains only parent - * EquivalenceMembers, and we have to translate top-level ones to get - * child members. We can skip such translations if we now see top-level - * ones, i.e., when top_parent_rel is NULL. See the - * find_relids_top_parents()'s definition for more details. - */ - top_parent_join_relids = find_relids_top_parents(root, join_relids); - /* * First, scan the EC to identify member values that are computable at the * outer rel, at the inner rel, or at this relation but not in either @@ -1870,21 +1788,10 @@ generate_join_implied_equalities_normal(PlannerInfo *root, * enforce that any newly computable members are all equal to each other * as well as to at least one input member, plus enforce at least one * outer-rel member equal to at least one inner-rel member. - * - * If we need to see child EquivalenceMembers, we access them via - * EquivalenceChildMemberIterator during the iteration. */ - setup_eclass_child_member_iterator(&it, ec); + setup_eclass_child_member_iterator(&it, root, ec, join_relids); while ((cur_em = eclass_child_member_iterator_next(&it)) != NULL) { - /* - * If child EquivalenceMembers may match the request, we add and - * iterate over them by calling iterate_child_rel_equivalences(). - */ - if (top_parent_join_relids != NULL && !cur_em->em_is_child && - bms_is_subset(cur_em->em_relids, top_parent_join_relids)) - iterate_child_rel_equivalences(&it, root, ec, cur_em, join_relids); - /* * We don't need to check explicitly for child EC members. This test * against join_relids will cause them to be ignored except when @@ -3058,8 +2965,8 @@ add_child_rel_equivalences(PlannerInfo *root, * combinations of children. (But add_child_join_rel_equivalences * may add targeted combinations for partitionwise-join purposes.) */ - /* Child members should not exist in ec_members */ - Assert(!cur_em->em_is_child); + Assert(!cur_em->em_is_child); /* Child members should not exist + * in ec_members */ /* * Consider only members that reference and can be computed at @@ -3111,15 +3018,6 @@ add_child_rel_equivalences(PlannerInfo *root, child_rel->eclass_child_members = lappend(child_rel->eclass_child_members, child_em); - /* - * We save the knowledge that 'child_em' can be translated - * using 'child_rel'. This knowledge is useful for - * iterate_child_rel_equivalences() to find child members from - * the given Relids. - */ - cur_em->em_child_relids = bms_add_member(cur_em->em_child_relids, - child_rel->relid); - /* Record this EC index for the child rel */ child_rel->eclass_indexes = bms_add_member(child_rel->eclass_indexes, i); } @@ -3192,8 +3090,8 @@ add_child_join_rel_equivalences(PlannerInfo *root, * We consider only original EC members here, not * already-transformed child members. */ - /* Child members should not exist in ec_members */ - Assert(!cur_em->em_is_child); + Assert(!cur_em->em_is_child); /* Child members should not exist + * in ec_members */ /* * We may ignore expressions that reference a single baserel, @@ -3246,16 +3144,6 @@ add_child_join_rel_equivalences(PlannerInfo *root, child_joinrel->eclass_child_members = lappend(child_joinrel->eclass_child_members, child_em); - /* - * We save the knowledge that 'child_em' can be translated - * using 'child_joinrel'. This knowledge is useful for - * iterate_child_rel_equivalences() to find child members from - * the given Relids. - */ - cur_em->em_child_joinrel_relids = - bms_add_member(cur_em->em_child_joinrel_relids, - child_joinrel->join_rel_list_index); - /* * Update the corresponding inverted indexes. */ @@ -3271,7 +3159,7 @@ add_child_join_rel_equivalences(PlannerInfo *root, * that have only such parent relations as em_relids are * already present in the ec_members, and so cannot be * candidates for additional iteration by - * iterate_child_rel_equivalences(). Since the function + * EquivalenceChildMemberIterator. Since the iterator * needs EquivalenceMembers whose em_relids has child * relations, skipping the update of this inverted index * allows for faster iteration. @@ -3341,15 +3229,6 @@ add_setop_child_rel_equivalences(PlannerInfo *root, RelOptInfo *child_rel, child_rel->eclass_child_members = lappend(child_rel->eclass_child_members, child_em); - /* - * We save the knowledge that 'child_em' can be translated using - * 'child_rel'. This knowledge is useful for - * iterate_child_rel_equivalences() to find child members from the - * given Relids. - */ - parent_em->em_child_relids = - bms_add_member(parent_em->em_child_relids, child_rel->relid); - /* * Make an UNION parent-child relationship between parent_em and * child_rel->relid. We record this relationship in @@ -3399,40 +3278,125 @@ add_setop_child_rel_equivalences(PlannerInfo *root, RelOptInfo *child_rel, */ void setup_eclass_child_member_iterator(EquivalenceChildMemberIterator *it, - EquivalenceClass *ec) + PlannerInfo *root, + EquivalenceClass *ec, + Relids relids) { + Bitmapset *matching_indexes; + int i; + + /* + * Initialize the iterator. + */ it->index = -1; it->modified = false; it->ec_members = ec->ec_members; -} -/* - * eclass_child_member_iterator_next - * Get a next EquivalenceMember from an EquivalenceChildMemberIterator 'it' - * that was setup by setup_eclass_child_member_iterator(). NULL is returned - * if there are no members left. - */ -EquivalenceMember * -eclass_child_member_iterator_next(EquivalenceChildMemberIterator *it) -{ - if (++it->index < list_length(it->ec_members)) - return list_nth_node(EquivalenceMember, it->ec_members, it->index); - return NULL; -} + /* + * If there are no child relations, there is nothing to do. This + * effectively avoids regression for non-partitioned cases. + */ + if (root->top_parent_relid_array == NULL) + return; -/* - * dispose_eclass_child_member_iterator - * Free any memory allocated by the iterator. - */ -void -dispose_eclass_child_member_iterator(EquivalenceChildMemberIterator *it) -{ /* - * XXX Should we use list_free()? I decided to use this style to take - * advantage of speculative execution. + * EquivalenceClass->ec_members has only parent EquivalenceMembers. Child + * members are translated using child RelOptInfos and stored in them. This + * is done in add_child_rel_equivalences(), + * add_child_join_rel_equivalences(), and + * add_setop_child_rel_equivalences(). To retrieve child + * EquivalenceMembers of some parent, we need to know which RelOptInfos + * have such child members. We can know this information using indexes + * like EquivalenceClassIndexes->joinrel_indexes. + * + * We use an inverted index mechanism to quickly iterate over the members + * whose em_relids is a subset of the given 'child_relids'. The inverted + * indexes store RelOptInfo indices that have EquivalenceMembers + * mentioning them. Taking the union of these indexes allows to find which + * RelOptInfos have the EquivalenceMember we are looking for. With this + * method, the em_relids of the newly iterated ones overlap the given + * 'child_relids', but may not be subsets, so the caller must check that + * they satisfy the desired condition. + * + * The above comments are about joinrels, and for simple rels, this + * mechanism is simpler. It is sufficient to simply add the child + * EquivalenceMembers of RelOptInfo to the iterator. + * + * We need to perform these steps for each of the two types of relations. */ - if (unlikely(it->modified)) - pfree(it->ec_members); + + /* + * Iterate over the given relids, adding child members for simple rels and + * taking union indexes for join rels. + */ + i = -1; + matching_indexes = NULL; + while ((i = bms_next_member(relids, i)) >= 0) + { + RelOptInfo *child_rel; + EquivalenceClassIndexes *indexes; + + /* + * If this relation is a parent, we don't have to do anything. + */ + if (root->top_parent_relid_array[i] == -1) + continue; + + /* + * Add child members that mention this relation to the iterator. + */ + child_rel = root->simple_rel_array[i]; + if (child_rel != NULL) + add_transformed_child_version(it, root, ec, child_rel); + + /* + * Union indexes for join rels. + */ + indexes = &root->eclass_indexes_array[i]; + matching_indexes = + bms_add_members(matching_indexes, indexes->joinrel_indexes); + } + + /* + * For join rels, add child members using 'matching_indexes'. + */ + i = -1; + while ((i = bms_next_member(matching_indexes, i)) >= 0) + { + RelOptInfo *child_joinrel = + list_nth_node(RelOptInfo, root->join_rel_list, i); + + Assert(child_joinrel != NULL); + + /* + * If this joinrel's Relids is not a subset of the given one, then the + * child EquivalenceMembers it holds should never be a subset either. + */ + if (bms_is_subset(child_joinrel->relids, relids)) + add_transformed_child_version(it, root, ec, child_joinrel); +#ifdef USE_ASSERT_CHECKING + else + { + /* + * Verify that the above comment is correct. + * + * NOTE: We may remove this assertion after the beta process. + */ + + ListCell *lc; + + foreach(lc, child_joinrel->eclass_child_members) + { + EquivalenceMember *child_em = lfirst_node(EquivalenceMember, lc); + + if (child_em->em_ec != ec) + continue; + Assert(!bms_is_subset(child_em->em_relids, relids)); + } + } +#endif + } + bms_free(matching_indexes); } /* @@ -3441,13 +3405,12 @@ dispose_eclass_child_member_iterator(EquivalenceChildMemberIterator *it) * the iterator. * * This function is expected to be called only from - * iterate_child_rel_equivalences(). + * setup_eclass_child_member_iterator(). */ static void add_transformed_child_version(EquivalenceChildMemberIterator *it, PlannerInfo *root, EquivalenceClass *ec, - EquivalenceMember *parent_em, RelOptInfo *child_rel) { ListCell *lc; @@ -3457,7 +3420,7 @@ add_transformed_child_version(EquivalenceChildMemberIterator *it, EquivalenceMember *child_em = lfirst_node(EquivalenceMember, lc); /* Skip unwanted EquivalenceMembers */ - if (child_em->em_parent != parent_em) + if (child_em->em_ec != ec) continue; /* @@ -3476,136 +3439,32 @@ add_transformed_child_version(EquivalenceChildMemberIterator *it, } /* - * iterate_child_rel_equivalences - * Add child EquivalenceMembers whose em_relids is a subset of the given - * 'child_relids' to the iterator. Note that this function may add false - * positives, so callers must check that the members that this function adds - * satisfy the desired condition. - * - * The transformation is done in add_transformed_child_version(). + * eclass_child_member_iterator_next + * Get a next EquivalenceMember from an EquivalenceChildMemberIterator 'it' + * that was setup by setup_eclass_child_member_iterator(). NULL is returned + * if there are no members left. */ -void -iterate_child_rel_equivalences(EquivalenceChildMemberIterator *it, - PlannerInfo *root, - EquivalenceClass *ec, - EquivalenceMember *parent_em, - Relids child_relids) +EquivalenceMember * +eclass_child_member_iterator_next(EquivalenceChildMemberIterator *it) { - /* The given EquivalenceMember should be parent */ - Assert(!parent_em->em_is_child); - - /* - * EquivalenceClass->ec_members has only parent EquivalenceMembers. Child - * members are translated using child RelOptInfos and stored in them. This - * is done in add_child_rel_equivalences() and - * add_child_join_rel_equivalences(). To retrieve child EquivalenceMembers - * of some parent, we need to know which RelOptInfos have such child - * members. We can know this information using indexes named - * EquivalenceMember->em_child_relids, - * EquivalenceMember->em_child_joinrel_relids, and - * EquivalenceClassIndexes->joinrel_indexes. - * - * We use an inverted index mechanism to quickly iterate over the members - * whose em_relids is a subset of the given 'child_relids'. The inverted - * indexes store RelOptInfo indices that have EquivalenceMembers - * mentioning them. Taking the union of these indexes allows to find which - * RelOptInfos have the EquivalenceMember we are looking for. With this - * method, the em_relids of the newly iterated ones overlap the given - * 'child_relids', but may not be subsets, so the caller must check that - * they satisfy the desired condition. - * - * The above comments are about joinrels, and for simple rels, this - * mechanism is simpler. It is sufficient to simply add the child - * EquivalenceMembers of RelOptInfo to the iterator. - * - * We need to perform these steps for each of the two types of relations. - */ - - /* - * First, we translate simple rels. - */ - if (!bms_is_empty(parent_em->em_child_relids)) - { - Relids matching_relids; - int i; - - /* Step 1: Get simple rels' Relids that have wanted EMs. */ - matching_relids = bms_intersect(parent_em->em_child_relids, - child_relids); - - /* Step 2: Fetch wanted EMs. */ - i = -1; - while ((i = bms_next_member(matching_relids, i)) >= 0) - { - RelOptInfo *child_rel = root->simple_rel_array[i]; - - Assert(child_rel != NULL); - add_transformed_child_version(it, root, ec, parent_em, child_rel); - } - bms_free(matching_relids); - } + if (++it->index < list_length(it->ec_members)) + return list_nth_node(EquivalenceMember, it->ec_members, it->index); + return NULL; +} +/* + * dispose_eclass_child_member_iterator + * Free any memory allocated by the iterator. + */ +void +dispose_eclass_child_member_iterator(EquivalenceChildMemberIterator *it) +{ /* - * Next, we try to translate join rels. + * XXX Should we use list_free()? I decided to use this style to take + * advantage of speculative execution. */ - if (!bms_is_empty(parent_em->em_child_joinrel_relids)) - { - Bitmapset *matching_indexes; - int i; - - /* Step 1: Get join rels' indices that have wanted EMs. */ - i = -1; - matching_indexes = NULL; - while ((i = bms_next_member(child_relids, i)) >= 0) - { - EquivalenceClassIndexes *indexes = &root->eclass_indexes_array[i]; - - matching_indexes = - bms_add_members(matching_indexes, indexes->joinrel_indexes); - } - matching_indexes = bms_int_members(matching_indexes, - parent_em->em_child_joinrel_relids); - - /* Step 2: Fetch wanted EMs. */ - i = -1; - while ((i = bms_next_member(matching_indexes, i)) >= 0) - { - RelOptInfo *child_joinrel = - list_nth_node(RelOptInfo, root->join_rel_list, i); - - Assert(child_joinrel != NULL); - - /* - * If this joinrel's Relids is not a subset of the given one, then - * the child EquivalenceMembers it holds should never be a subset - * either. - */ - if (bms_is_subset(child_joinrel->relids, child_relids)) - add_transformed_child_version(it, root, ec, parent_em, child_joinrel); -#ifdef USE_ASSERT_CHECKING - else - { - /* - * Verify that the above comment is correct. - * - * NOTE: We may remove this assertion after the beta process. - */ - - ListCell *lc; - - foreach(lc, child_joinrel->eclass_child_members) - { - EquivalenceMember *child_em = lfirst_node(EquivalenceMember, lc); - - if (child_em->em_parent != parent_em) - continue; - Assert(!bms_is_subset(child_em->em_relids, child_relids)); - } - } -#endif - } - bms_free(matching_indexes); - } + if (unlikely(it->modified)) + pfree(it->ec_members); } @@ -3641,8 +3500,7 @@ generate_implied_equalities_for_column(PlannerInfo *root, { List *result = NIL; bool is_child_rel = (rel->reloptkind == RELOPT_OTHER_MEMBER_REL); - Relids parent_relids, - top_parent_rel_relids; + Relids parent_relids; int i; /* Should be OK to rely on eclass_indexes */ @@ -3651,16 +3509,6 @@ generate_implied_equalities_for_column(PlannerInfo *root, /* Indexes are available only on base or "other" member relations. */ Assert(IS_SIMPLE_REL(rel)); - /* - * First, we translate the given Relids to their top-level parents. This - * is required because an EquivalenceClass contains only parent - * EquivalenceMembers, and we have to translate top-level ones to get - * child members. We can skip such translations if we now see top-level - * ones, i.e., when top_parent_rel is NULL. See the - * find_relids_top_parents()'s definition for more details. - */ - top_parent_rel_relids = find_relids_top_parents(root, rel->relids); - /* If it's a child rel, we'll need to know what its parent(s) are */ if (is_child_rel) parent_relids = find_childrel_parents(root, rel); @@ -3694,20 +3542,10 @@ generate_implied_equalities_for_column(PlannerInfo *root, * column gets matched to. This is annoying but it only happens in * corner cases, so for now we live with just reporting the first * match. See also get_eclass_for_sort_expr.) - * - * If we need to see child EquivalenceMembers, we access them via - * EquivalenceChildMemberIterator during the iteration. */ - setup_eclass_child_member_iterator(&it, cur_ec); + setup_eclass_child_member_iterator(&it, root, cur_ec, rel->relids); while ((cur_em = eclass_child_member_iterator_next(&it)) != NULL) { - /* - * If child EquivalenceMembers may match the request, we add and - * iterate over them by calling iterate_child_rel_equivalences(). - */ - if (top_parent_rel_relids != NULL && !cur_em->em_is_child && - bms_equal(cur_em->em_relids, top_parent_rel_relids)) - iterate_child_rel_equivalences(&it, root, cur_ec, cur_em, rel->relids); if (bms_equal(cur_em->em_relids, rel->relids) && callback(root, rel, cur_ec, cur_em, callback_arg)) break; diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c index 7ced5e33798..d19b45a1293 100644 --- a/src/backend/optimizer/path/indxpath.c +++ b/src/backend/optimizer/path/indxpath.c @@ -3743,19 +3743,8 @@ match_pathkeys_to_index(PlannerInfo *root, IndexOptInfo *index, List *pathkeys, List **orderby_clauses_p, List **clause_columns_p) { - Relids top_parent_index_relids; ListCell *lc1; - /* - * First, we translate the given Relids to their top-level parents. This - * is required because an EquivalenceClass contains only parent - * EquivalenceMembers, and we have to translate top-level ones to get - * child members. We can skip such translations if we now see top-level - * ones, i.e., when top_parent_rel is NULL. See the - * find_relids_top_parents()'s definition for more details. - */ - top_parent_index_relids = find_relids_top_parents(root, index->rel->relids); - *orderby_clauses_p = NIL; /* set default results */ *clause_columns_p = NIL; @@ -3787,36 +3776,17 @@ match_pathkeys_to_index(PlannerInfo *root, IndexOptInfo *index, List *pathkeys, * child member of more than one EC. Therefore, the same index could * be considered to match more than one pathkey list, which is OK * here. See also get_eclass_for_sort_expr.) - * - * If we need to see child EquivalenceMembers, we access them via - * EquivalenceChildMemberIterator during the iteration. */ - setup_eclass_child_member_iterator(&it, pathkey->pk_eclass); + setup_eclass_child_member_iterator(&it, root, pathkey->pk_eclass, + index->rel->relids); while ((member = eclass_child_member_iterator_next(&it))) { int indexcol; - /* - * If child EquivalenceMembers may match the request, we add and - * iterate over them by calling iterate_child_rel_equivalences(). - */ - if (top_parent_index_relids != NULL && !member->em_is_child && - bms_equal(member->em_relids, top_parent_index_relids)) - iterate_child_rel_equivalences(&it, root, pathkey->pk_eclass, member, - index->rel->relids); - /* No possibility of match if it references other relations */ - if (!member->em_is_child && - !bms_equal(member->em_relids, index->rel->relids)) + if (!bms_equal(member->em_relids, index->rel->relids)) continue; - /* - * If this EquivalenceMember is a child, i.e., translated above, - * it should match the request. We cannot assert this if a request - * is bms_is_subset(). - */ - Assert(bms_equal(member->em_relids, index->rel->relids)); - /* * We allow any column of the index to match each pathkey; they * don't have to match left-to-right as you might expect. This is diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c index 48517ddaf86..c8e535617b8 100644 --- a/src/backend/optimizer/util/relnode.c +++ b/src/backend/optimizer/util/relnode.c @@ -1587,48 +1587,6 @@ find_childrel_parents(PlannerInfo *root, RelOptInfo *rel) } -/* - * find_relids_top_parents_slow - * Slow path of find_relids_top_parents() macro. - * - * Do not call this directly; use the macro instead. See the macro comment for - * more details. - */ -Relids -find_relids_top_parents_slow(PlannerInfo *root, Relids relids) -{ - Index *top_parent_relid_array = root->top_parent_relid_array; - Relids result; - bool is_top_parent; - int i; - - /* This function should be called in the slow path */ - Assert(top_parent_relid_array != NULL); - - result = NULL; - is_top_parent = true; - i = -1; - while ((i = bms_next_member(relids, i)) >= 0) - { - int top_parent_relid = (int) top_parent_relid_array[i]; - - if (top_parent_relid == -1) - top_parent_relid = i; /* 'i' has no parents, so add itself */ - else if (top_parent_relid != i) - is_top_parent = false; - result = bms_add_member(result, top_parent_relid); - } - - if (is_top_parent) - { - bms_free(result); - return NULL; - } - - return result; -} - - /* * get_baserel_parampathinfo * Get the ParamPathInfo for a parameterized path for a base relation, diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h index a408051faba..8b4c8319aad 100644 --- a/src/include/nodes/pathnodes.h +++ b/src/include/nodes/pathnodes.h @@ -1527,35 +1527,32 @@ typedef struct EquivalenceMember bool em_is_child; /* derived version for a child relation? */ Oid em_datatype; /* the "nominal type" used by the opfamily */ JoinDomain *em_jdomain; /* join domain containing the source clause */ - Relids em_child_relids; /* all relids of child rels */ - Bitmapset *em_child_joinrel_relids; /* indexes in root->join_rel_list - * of join rel children */ /* if em_is_child is true, this links to corresponding EM for top parent */ struct EquivalenceMember *em_parent pg_node_attr(read_write_ignore); + EquivalenceClass *em_ec; /* EquivalenceClass which has this member */ } EquivalenceMember; /* * EquivalenceChildMemberIterator * - * EquivalenceClass has only parent EquivalenceMembers, so we need to translate - * child members if necessary. EquivalenceChildMemberIterator provides a way to - * iterate over translated child members during the loop in addition to all of - * the parent EquivalenceMembers. + * EquivalenceClass contains only parent members. Use the + * EquivalenceChildMemberIterator to iterate over child members whose em_relids + * is a subset of the specified 'child_relids' in addition to the parent + * members. Note that the iterator may yield false positives, so callers must + * verify that each member satisfies the condition. * * The most common way to use this struct is as follows: * ----- + * PlannerInfo *root = given; * EquivalenceClass *ec = given; * Relids rel = given; * EquivalenceChildMemberIterator it; * EquivalenceMember *em; * - * setup_eclass_child_member_iterator(&it, ec); + * setup_eclass_child_member_iterator(&it, root, ec, rel); * while ((em = eclass_child_member_iterator_next(&it)) != NULL) * { * use em ...; - * if (we need to iterate over child EquivalenceMembers) - * iterate_child_rel_equivalences(&it, root, ec, em, rel); - * use em ...; * } * dispose_eclass_child_member_iterator(&it); * ----- diff --git a/src/include/optimizer/pathnode.h b/src/include/optimizer/pathnode.h index b6208928bf9..719be3897f6 100644 --- a/src/include/optimizer/pathnode.h +++ b/src/include/optimizer/pathnode.h @@ -331,24 +331,6 @@ extern Relids min_join_parameterization(PlannerInfo *root, extern RelOptInfo *fetch_upper_rel(PlannerInfo *root, UpperRelationKind kind, Relids relids); extern Relids find_childrel_parents(PlannerInfo *root, RelOptInfo *rel); - -/* - * find_relids_top_parents - * Compute the set of top-parent relids of rel. - * - * Replaces all Relids appearing in the given 'relids' as their top-level - * parents. The result will be NULL if and only if all of the given relids are - * top-level. - * - * The motivation for having this feature as a macro rather than a function is - * that Relids are top-level in most cases. We can quickly determine when - * root->top_parent_relid_array is NULL. - */ -#define find_relids_top_parents(root, relids) \ - ((root)->top_parent_relid_array == NULL \ - ? NULL : find_relids_top_parents_slow(root, relids)) -extern Relids find_relids_top_parents_slow(PlannerInfo *root, Relids relids); - extern ParamPathInfo *get_baserel_parampathinfo(PlannerInfo *root, RelOptInfo *baserel, Relids required_outer); diff --git a/src/include/optimizer/paths.h b/src/include/optimizer/paths.h index a91fb41335a..07525dca66d 100644 --- a/src/include/optimizer/paths.h +++ b/src/include/optimizer/paths.h @@ -184,14 +184,11 @@ extern void add_setop_child_rel_equivalences(PlannerInfo *root, List *child_tlist, List *setop_pathkeys); extern void setup_eclass_child_member_iterator(EquivalenceChildMemberIterator *it, - EquivalenceClass *ec); + PlannerInfo *root, + EquivalenceClass *ec, + Relids relids); extern EquivalenceMember *eclass_child_member_iterator_next(EquivalenceChildMemberIterator *it); extern void dispose_eclass_child_member_iterator(EquivalenceChildMemberIterator *it); -extern void iterate_child_rel_equivalences(EquivalenceChildMemberIterator *it, - PlannerInfo *root, - EquivalenceClass *ec, - EquivalenceMember *parent_em, - Relids child_relids); extern List *generate_implied_equalities_for_column(PlannerInfo *root, RelOptInfo *rel, ec_matches_callback_type callback,