From 413fa3487560a3f15bfdf0062169856cb0892fb2 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 v28 5/7] 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 | 51 ++++++++++++++++++++++---
 src/backend/optimizer/util/inherit.c    |  8 +++-
 src/backend/optimizer/util/relnode.c    | 10 +++--
 src/include/nodes/pathnodes.h           |  2 +-
 4 files changed, 59 insertions(+), 12 deletions(-)

diff --git a/src/backend/optimizer/path/equivclass.c b/src/backend/optimizer/path/equivclass.c
index e30d931f19c..022f20020af 100644
--- a/src/backend/optimizer/path/equivclass.c
+++ b/src/backend/optimizer/path/equivclass.c
@@ -3288,7 +3288,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;
@@ -3305,12 +3307,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
+		 * add_transformed_child_version() 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 3c2198ea5bd..7b2390687e0 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 ca1d7e91bff..fcd57c1f3e9 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 c068dc1b6c6..9c2d284c079 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

