From f145ef33bd40507148a31ba0a7c5d084c2d928c0 Mon Sep 17 00:00:00 2001
From: Yuya Watari <watari.yuya@gmail.com>
Date: Tue, 27 Aug 2024 13:20:29 +0900
Subject: [PATCH v31 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 | 46 ++++++++++++++++++++-----
 src/backend/optimizer/util/inherit.c    |  8 +++--
 src/backend/optimizer/util/relnode.c    |  8 +++--
 src/include/nodes/pathnodes.h           |  2 +-
 4 files changed, 51 insertions(+), 13 deletions(-)

diff --git a/src/backend/optimizer/path/equivclass.c b/src/backend/optimizer/path/equivclass.c
index aebf809a645..26834953a89 100644
--- a/src/backend/optimizer/path/equivclass.c
+++ b/src/backend/optimizer/path/equivclass.c
@@ -2976,7 +2976,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,
@@ -3013,7 +3013,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;
@@ -3030,12 +3032,40 @@ 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);
+
+		/*
+		 * 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);
 	}
@@ -3121,7 +3151,7 @@ setup_eclass_child_member_iterator(EquivalenceChildMemberIterator *it,
 		/*
 		 * If this relation is a parent, we don't have to do anything.
 		 */
-		if (root->top_parent_relid_array[i] == 0)
+		if (root->top_parent_relid_array[i] == -1)
 			continue;
 
 		/*
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 a07bca8431b..c8e535617b8 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
 	{
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index 6bdac3bad2c..645c5898d4d 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -276,7 +276,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

