From 7270edf4d12379d717d1674d49181eed4a8a7dc6 Mon Sep 17 00:00:00 2001 From: Yuya Watari Date: Tue, 27 Aug 2024 13:20:29 +0900 Subject: [PATCH v30 2/4] Resolve conflict with commit 66c0185 This commit resolves a conflict with 66c0185, which added add_setop_child_rel_equivalences(). The function creates child EquivalenceMembers to efficiently implement UNION queries. This commit adjusts our optimization to handle this type of child EquivalenceMembers based on UNION parent-child relationships. --- src/backend/optimizer/path/equivclass.c | 53 +++++++++++++++++++++---- src/backend/optimizer/util/inherit.c | 8 +++- src/backend/optimizer/util/relnode.c | 10 +++-- src/include/nodes/pathnodes.h | 2 +- 4 files changed, 60 insertions(+), 13 deletions(-) diff --git a/src/backend/optimizer/path/equivclass.c b/src/backend/optimizer/path/equivclass.c index 43711eb303a..5f81dcaf87d 100644 --- a/src/backend/optimizer/path/equivclass.c +++ b/src/backend/optimizer/path/equivclass.c @@ -3088,7 +3088,7 @@ add_child_join_rel_equivalences(PlannerInfo *root, * relations, skipping the update of this inverted index * allows for faster iteration. */ - if (root->top_parent_relid_array[j] == 0) + if (root->top_parent_relid_array[j] == -1) continue; indexes->joinrel_indexes = bms_add_member(indexes->joinrel_indexes, @@ -3125,7 +3125,9 @@ add_setop_child_rel_equivalences(PlannerInfo *root, RelOptInfo *child_rel, { TargetEntry *tle = lfirst_node(TargetEntry, lc); EquivalenceMember *parent_em; + EquivalenceMember *child_em; PathKey *pk; + Index parent_relid; if (tle->resjunk) continue; @@ -3142,12 +3144,49 @@ add_setop_child_rel_equivalences(PlannerInfo *root, RelOptInfo *child_rel, * likewise, the JoinDomain can be that of the initial member of the * Pathkey's EquivalenceClass. */ - add_parent_eq_member(pk->pk_eclass, - tle->expr, - child_rel->relids, - parent_em->em_jdomain, - parent_em, - exprType((Node *) tle->expr)); + child_em = make_eq_member(pk->pk_eclass, + tle->expr, + child_rel->relids, + parent_em->em_jdomain, + parent_em, + exprType((Node *) tle->expr)); + 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 + * root->top_parent_relid_array, which generally has AppendRelInfo + * relationships. We use the same array here to retrieve UNION child + * members. + * + * XXX Here we treat the first member of parent_em->em_relids as a + * parent of child_rel. Is this correct? What happens if + * parent_em->em_relids has two or more members? + */ + parent_relid = bms_next_member(parent_em->em_relids, -1); + if (root->top_parent_relid_array == NULL) + { + /* + * If the array is NULL, allocate it here. + */ + root->top_parent_relid_array = (Index *) + palloc(root->simple_rel_array_size * sizeof(Index)); + MemSet(root->top_parent_relid_array, -1, + sizeof(Index) * root->simple_rel_array_size); + } + Assert(root->top_parent_relid_array[child_rel->relid] == -1 || + root->top_parent_relid_array[child_rel->relid] == parent_relid); + root->top_parent_relid_array[child_rel->relid] = parent_relid; lc2 = lnext(setop_pathkeys, lc2); } diff --git a/src/backend/optimizer/util/inherit.c b/src/backend/optimizer/util/inherit.c index 734d54a7305..08cd39a6c85 100644 --- a/src/backend/optimizer/util/inherit.c +++ b/src/backend/optimizer/util/inherit.c @@ -582,9 +582,13 @@ expand_single_inheritance_child(PlannerInfo *root, RangeTblEntry *parentrte, * Find a top parent rel's index and save it to top_parent_relid_array. */ if (root->top_parent_relid_array == NULL) + { root->top_parent_relid_array = - (Index *) palloc0(root->simple_rel_array_size * sizeof(Index)); - Assert(root->top_parent_relid_array[childRTindex] == 0); + (Index *) palloc(root->simple_rel_array_size * sizeof(Index)); + MemSet(root->top_parent_relid_array, -1, + sizeof(Index) * root->simple_rel_array_size); + } + Assert(root->top_parent_relid_array[childRTindex] == -1); topParentRTindex = parentRTindex; while (root->append_rel_array[topParentRTindex] != NULL && root->append_rel_array[topParentRTindex]->parent_relid != 0) diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c index 0ee1476b471..48517ddaf86 100644 --- a/src/backend/optimizer/util/relnode.c +++ b/src/backend/optimizer/util/relnode.c @@ -133,7 +133,9 @@ setup_simple_rel_arrays(PlannerInfo *root) root->append_rel_array = (AppendRelInfo **) palloc0(size * sizeof(AppendRelInfo *)); root->top_parent_relid_array = (Index *) - palloc0(size * sizeof(Index)); + palloc(size * sizeof(Index)); + MemSet(root->top_parent_relid_array, -1, + sizeof(Index) * size); /* * append_rel_array is filled with any already-existing AppendRelInfos, @@ -206,7 +208,9 @@ expand_planner_arrays(PlannerInfo *root, int add_size) root->append_rel_array = repalloc0_array(root->append_rel_array, AppendRelInfo *, root->simple_rel_array_size, new_size); root->top_parent_relid_array = - repalloc0_array(root->top_parent_relid_array, Index, root->simple_rel_array_size, new_size); + repalloc_array(root->top_parent_relid_array, Index, new_size); + MemSet(root->top_parent_relid_array + root->simple_rel_array_size, -1, + sizeof(Index) * add_size); } else { @@ -1608,7 +1612,7 @@ find_relids_top_parents_slow(PlannerInfo *root, Relids relids) { int top_parent_relid = (int) top_parent_relid_array[i]; - if (top_parent_relid == 0) + 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; diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h index dfcbd613156..62c4f7e214c 100644 --- a/src/include/nodes/pathnodes.h +++ b/src/include/nodes/pathnodes.h @@ -260,7 +260,7 @@ struct PlannerInfo /* * top_parent_relid_array is the same length as simple_rel_array and holds * the top-level parent indexes of the corresponding rels within - * simple_rel_array. The element can be zero if the rel has no parents, + * simple_rel_array. The element can be -1 if the rel has no parents, * i.e., is itself in a top-level. */ Index *top_parent_relid_array pg_node_attr(read_write_ignore); -- 2.45.2.windows.1