diff-v34-v35.txt

text/plain

Filename: diff-v34-v35.txt
Type: text/plain
Part: 0
Message: Re: [PoC] Reducing planning time when tables have many partitions
diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c
index dbf92c9b7ca..adcf6417468 100644
--- a/contrib/postgres_fdw/postgres_fdw.c
+++ b/contrib/postgres_fdw/postgres_fdw.c
@@ -7829,11 +7829,11 @@ EquivalenceMember *
 find_em_for_rel(PlannerInfo *root, EquivalenceClass *ec, RelOptInfo *rel)
 {
 	PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) rel->fdw_private;
-	EquivalenceAllMemberIterator it;
+	EquivalenceMemberIterator it;
 	EquivalenceMember *em;
 
-	setup_eclass_all_member_iterator_for_relids(&it, root, ec, rel->relids);
-	while ((em = eclass_all_member_iterator_for_relids_next(&it)) != NULL)
+	setup_eclass_member_iterator_with_children(&it, root, ec, rel->relids);
+	while ((em = eclass_member_iterator_next(&it)) != NULL)
 	{
 		/*
 		 * Note we require !bms_is_empty, else we'd accept constant
@@ -7845,7 +7845,7 @@ find_em_for_rel(PlannerInfo *root, EquivalenceClass *ec, RelOptInfo *rel)
 			is_foreign_expr(root, rel, em->em_expr))
 			return em;
 	}
-	dispose_eclass_all_member_iterator_for_relids(&it);
+	dispose_eclass_member_iterator(&it);
 
 	return NULL;
 }
diff --git a/src/backend/optimizer/path/equivclass.c b/src/backend/optimizer/path/equivclass.c
index c6ecfb874c8..1ffd2ce0a04 100644
--- a/src/backend/optimizer/path/equivclass.c
+++ b/src/backend/optimizer/path/equivclass.c
@@ -38,10 +38,10 @@ static EquivalenceMember *make_eq_member(EquivalenceClass *ec,
 										 JoinDomain *jdomain,
 										 EquivalenceMember *parent,
 										 Oid datatype);
-static EquivalenceMember *add_parent_eq_member(EquivalenceClass *ec,
-											   Expr *expr, Relids relids,
-											   JoinDomain *jdomain,
-											   Oid datatype);
+static EquivalenceMember *add_eq_member(EquivalenceClass *ec,
+										Expr *expr, Relids relids,
+										JoinDomain *jdomain,
+										Oid datatype);
 static void add_eq_source(PlannerInfo *root, EquivalenceClass *ec,
 						  RestrictInfo *rinfo);
 static void add_eq_derive(PlannerInfo *root, EquivalenceClass *ec,
@@ -76,7 +76,7 @@ static bool reconsider_outer_join_clause(PlannerInfo *root,
 static bool reconsider_full_join_clause(PlannerInfo *root,
 										OuterJoinClauseInfo *ojcinfo);
 static JoinDomain *find_join_domain(PlannerInfo *root, Relids relids);
-static void add_eclass_child_members_to_iterator(EquivalenceAllMemberIterator *it,
+static void add_eclass_child_members_to_iterator(EquivalenceMemberIterator *it,
 												 PlannerInfo *root,
 												 EquivalenceClass *ec,
 												 RelOptInfo *child_rel);
@@ -280,7 +280,8 @@ process_equivalence(PlannerInfo *root,
 		{
 			EquivalenceMember *cur_em = (EquivalenceMember *) lfirst(lc2);
 
-			Assert(!cur_em->em_is_child);	/* no children yet */
+			/* Child members should not exist in ec_members */
+			Assert(!cur_em->em_is_child);
 
 			/*
 			 * Match constants only within the same JoinDomain (see
@@ -388,8 +389,8 @@ process_equivalence(PlannerInfo *root,
 	else if (ec1)
 	{
 		/* Case 3: add item2 to ec1 */
-		em2 = add_parent_eq_member(ec1, item2, item2_relids,
-								   jdomain, item2_type);
+		em2 = add_eq_member(ec1, item2, item2_relids,
+							jdomain, item2_type);
 		ec1->ec_min_security = Min(ec1->ec_min_security,
 								   restrictinfo->security_level);
 		ec1->ec_max_security = Max(ec1->ec_max_security,
@@ -406,8 +407,8 @@ process_equivalence(PlannerInfo *root,
 	else if (ec2)
 	{
 		/* Case 3: add item1 to ec2 */
-		em1 = add_parent_eq_member(ec2, item1, item1_relids,
-								   jdomain, item1_type);
+		em1 = add_eq_member(ec2, item1, item1_relids,
+							jdomain, item1_type);
 		ec2->ec_min_security = Min(ec2->ec_min_security,
 								   restrictinfo->security_level);
 		ec2->ec_max_security = Max(ec2->ec_max_security,
@@ -439,10 +440,10 @@ process_equivalence(PlannerInfo *root,
 		ec->ec_min_security = restrictinfo->security_level;
 		ec->ec_max_security = restrictinfo->security_level;
 		ec->ec_merged = NULL;
-		em1 = add_parent_eq_member(ec, item1, item1_relids,
-								   jdomain, item1_type);
-		em2 = add_parent_eq_member(ec, item2, item2_relids,
-								   jdomain, item2_type);
+		em1 = add_eq_member(ec, item1, item1_relids,
+							jdomain, item1_type);
+		em2 = add_eq_member(ec, item2, item2_relids,
+							jdomain, item2_type);
 
 		root->eq_classes = lappend(root->eq_classes, ec);
 
@@ -576,7 +577,7 @@ make_eq_member(EquivalenceClass *ec, Expr *expr, Relids relids,
 }
 
 /*
- * add_parent_eq_member - build a new parent EquivalenceMember and add it to an EC
+ * add_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
@@ -585,8 +586,8 @@ make_eq_member(EquivalenceClass *ec, Expr *expr, Relids relids,
  * to see how to add child members.
  */
 static EquivalenceMember *
-add_parent_eq_member(EquivalenceClass *ec, Expr *expr, Relids relids,
-					 JoinDomain *jdomain, Oid datatype)
+add_eq_member(EquivalenceClass *ec, Expr *expr, Relids relids,
+			  JoinDomain *jdomain, Oid datatype)
 {
 	EquivalenceMember *em = make_eq_member(ec, expr, relids, jdomain,
 										   NULL, datatype);
@@ -821,7 +822,7 @@ get_eclass_for_sort_expr(PlannerInfo *root,
 	foreach(lc1, root->eq_classes)
 	{
 		EquivalenceClass *cur_ec = (EquivalenceClass *) lfirst(lc1);
-		EquivalenceAllMemberIterator it;
+		EquivalenceMemberIterator it;
 		EquivalenceMember *cur_em;
 
 		/*
@@ -837,8 +838,8 @@ get_eclass_for_sort_expr(PlannerInfo *root,
 		if (!equal(opfamilies, cur_ec->ec_opfamilies))
 			continue;
 
-		setup_eclass_all_member_iterator_for_relids(&it, root, cur_ec, rel);
-		while ((cur_em = eclass_all_member_iterator_for_relids_next(&it)) != NULL)
+		setup_eclass_member_iterator_with_children(&it, root, cur_ec, rel);
+		while ((cur_em = eclass_member_iterator_next(&it)) != NULL)
 		{
 			/*
 			 * Ignore child members unless they match the request.
@@ -858,7 +859,7 @@ get_eclass_for_sort_expr(PlannerInfo *root,
 				equal(expr, cur_em->em_expr))
 				return cur_ec;	/* Match! */
 		}
-		dispose_eclass_all_member_iterator_for_relids(&it);
+		dispose_eclass_member_iterator(&it);
 	}
 
 	/* No match; does caller want a NULL result? */
@@ -895,14 +896,14 @@ get_eclass_for_sort_expr(PlannerInfo *root,
 	 */
 	expr_relids = pull_varnos(root, (Node *) expr);
 
-	newem = add_parent_eq_member(newec, copyObject(expr), expr_relids,
-								 jdomain, opcintype);
+	newem = add_eq_member(newec, copyObject(expr), expr_relids,
+						  jdomain, opcintype);
 
 	/*
-	 * add_parent_eq_member doesn't check for volatile functions,
-	 * set-returning functions, aggregates, or window functions, but such
-	 * could appear in sort expressions; so we have to check whether its
-	 * const-marking was correct.
+	 * add_eq_member doesn't check for volatile functions, set-returning
+	 * functions, aggregates, or window functions, but such could appear in
+	 * sort expressions; so we have to check whether its const-marking was
+	 * correct.
 	 */
 	if (newec->ec_has_const)
 	{
@@ -970,15 +971,15 @@ find_ec_member_matching_expr(PlannerInfo *root, EquivalenceClass *ec,
 							 Expr *expr,
 							 Relids relids)
 {
-	EquivalenceAllMemberIterator it;
+	EquivalenceMemberIterator it;
 	EquivalenceMember *em;
 
 	/* We ignore binary-compatible relabeling on both ends */
 	while (expr && IsA(expr, RelabelType))
 		expr = ((RelabelType *) expr)->arg;
 
-	setup_eclass_all_member_iterator_for_relids(&it, root, ec, relids);
-	while ((em = eclass_all_member_iterator_for_relids_next(&it)) != NULL)
+	setup_eclass_member_iterator_with_children(&it, root, ec, relids);
+	while ((em = eclass_member_iterator_next(&it)) != NULL)
 	{
 		Expr	   *emexpr;
 
@@ -1006,7 +1007,7 @@ find_ec_member_matching_expr(PlannerInfo *root, EquivalenceClass *ec,
 		if (equal(emexpr, expr))
 			return em;
 	}
-	dispose_eclass_all_member_iterator_for_relids(&it);
+	dispose_eclass_member_iterator(&it);
 
 	return NULL;
 }
@@ -1049,7 +1050,7 @@ find_computable_ec_member(PlannerInfo *root,
 						  bool require_parallel_safe)
 {
 	List	   *exprvars;
-	EquivalenceAllMemberIterator it;
+	EquivalenceMemberIterator it;
 	EquivalenceMember *em;
 
 	/*
@@ -1064,8 +1065,8 @@ find_computable_ec_member(PlannerInfo *root,
 							   PVC_INCLUDE_PLACEHOLDERS |
 							   PVC_INCLUDE_CONVERTROWTYPES);
 
-	setup_eclass_all_member_iterator_for_relids(&it, root, ec, relids);
-	while ((em = eclass_all_member_iterator_for_relids_next(&it)) != NULL)
+	setup_eclass_member_iterator_with_children(&it, root, ec, relids);
+	while ((em = eclass_member_iterator_next(&it)) != NULL)
 	{
 		List	   *emvars;
 		ListCell   *lc2;
@@ -1110,7 +1111,7 @@ find_computable_ec_member(PlannerInfo *root,
 
 		return em;				/* found usable expression */
 	}
-	dispose_eclass_all_member_iterator_for_relids(&it);
+	dispose_eclass_member_iterator(&it);
 
 	return NULL;
 }
@@ -1373,7 +1374,8 @@ generate_base_implied_equalities_const(PlannerInfo *root,
 		Oid			eq_op;
 		RestrictInfo *rinfo;
 
-		Assert(!cur_em->em_is_child);	/* no children yet */
+		Assert(!cur_em->em_is_child);	/* Child members should not exist in
+										 * ec_members */
 		if (cur_em == const_em)
 			continue;
 		eq_op = select_equality_operator(ec,
@@ -1443,7 +1445,8 @@ generate_base_implied_equalities_no_const(PlannerInfo *root,
 		EquivalenceMember *cur_em = (EquivalenceMember *) lfirst(lc);
 		int			relid;
 
-		Assert(!cur_em->em_is_child);	/* no children yet */
+		Assert(!cur_em->em_is_child);	/* Child members should not exist in
+										 * ec_members */
 		if (!bms_get_singleton_member(cur_em->em_relids, &relid))
 			continue;
 		Assert(relid < root->simple_rel_array_size);
@@ -1777,7 +1780,7 @@ generate_join_implied_equalities_normal(PlannerInfo *root,
 	List	   *new_members = NIL;
 	List	   *outer_members = NIL;
 	List	   *inner_members = NIL;
-	EquivalenceAllMemberIterator it;
+	EquivalenceMemberIterator it;
 	EquivalenceMember *cur_em;
 
 	/*
@@ -1789,8 +1792,8 @@ generate_join_implied_equalities_normal(PlannerInfo *root,
 	 * 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.
 	 */
-	setup_eclass_all_member_iterator_for_relids(&it, root, ec, join_relids);
-	while ((cur_em = eclass_all_member_iterator_for_relids_next(&it)) != NULL)
+	setup_eclass_member_iterator_with_children(&it, root, ec, join_relids);
+	while ((cur_em = eclass_member_iterator_next(&it)) != NULL)
 	{
 		/*
 		 * We don't need to check explicitly for child EC members.  This test
@@ -1807,7 +1810,7 @@ generate_join_implied_equalities_normal(PlannerInfo *root,
 		else
 			new_members = lappend(new_members, cur_em);
 	}
-	dispose_eclass_all_member_iterator_for_relids(&it);
+	dispose_eclass_member_iterator(&it);
 
 	/*
 	 * First, select the joinclause if needed.  We can equate any one outer
@@ -2406,7 +2409,8 @@ reconsider_outer_join_clause(PlannerInfo *root, OuterJoinClauseInfo *ojcinfo,
 		{
 			EquivalenceMember *cur_em = (EquivalenceMember *) lfirst(lc2);
 
-			Assert(!cur_em->em_is_child);	/* no children yet */
+			Assert(!cur_em->em_is_child);	/* Child members should not exist
+											 * in ec_members */
 			if (equal(outervar, cur_em->em_expr))
 			{
 				match = true;
@@ -2533,7 +2537,8 @@ reconsider_full_join_clause(PlannerInfo *root, OuterJoinClauseInfo *ojcinfo)
 		foreach(lc2, cur_ec->ec_members)
 		{
 			coal_em = (EquivalenceMember *) lfirst(lc2);
-			Assert(!coal_em->em_is_child);	/* no children yet */
+			Assert(!coal_em->em_is_child);	/* Child members should not exist
+											 * in ec_members */
 			if (IsA(coal_em->em_expr, CoalesceExpr))
 			{
 				CoalesceExpr *cexpr = (CoalesceExpr *) coal_em->em_expr;
@@ -2630,7 +2635,6 @@ reconsider_full_join_clause(PlannerInfo *root, OuterJoinClauseInfo *ojcinfo)
 		if (matchleft && matchright)
 		{
 			cur_ec->ec_members = list_delete_nth_cell(cur_ec->ec_members, coal_idx);
-			Assert(!bms_is_empty(coal_em->em_relids));
 			return true;
 		}
 
@@ -2752,8 +2756,8 @@ exprs_known_equal(PlannerInfo *root, Node *item1, Node *item2, Oid opfamily)
 		{
 			EquivalenceMember *em = (EquivalenceMember *) lfirst(lc2);
 
-			/* Child members should not exist in ec_members */
-			Assert(!em->em_is_child);
+			Assert(!em->em_is_child);	/* Child members should not exist in
+										 * ec_members */
 			if (equal(item1, em->em_expr))
 				item1member = true;
 			else if (equal(item2, em->em_expr))
@@ -2957,16 +2961,8 @@ add_child_rel_equivalences(PlannerInfo *root,
 			if (cur_em->em_is_const)
 				continue;		/* ignore consts here */
 
-			/*
-			 * We consider only original EC members here, not
-			 * 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.  (But add_child_join_rel_equivalences
-			 * may add targeted combinations for partitionwise-join purposes.)
-			 */
-			Assert(!cur_em->em_is_child);	/* Child members should not exist
-											 * in ec_members */
+			/* Child members should not exist in ec_members */
+			Assert(!cur_em->em_is_child);
 
 			/*
 			 * Consider only members that reference and can be computed at
@@ -3045,7 +3041,6 @@ add_child_join_rel_equivalences(PlannerInfo *root,
 	Relids		child_relids = child_joinrel->relids;
 	Bitmapset  *matching_ecs;
 	MemoryContext oldcontext;
-	ListCell   *lc;
 	int			i;
 
 	Assert(IS_JOIN_REL(child_joinrel) && IS_JOIN_REL(parent_joinrel));
@@ -3067,6 +3062,7 @@ add_child_join_rel_equivalences(PlannerInfo *root,
 	while ((i = bms_next_member(matching_ecs, i)) >= 0)
 	{
 		EquivalenceClass *cur_ec = (EquivalenceClass *) list_nth(root->eq_classes, i);
+		ListCell   *lc;
 
 		/*
 		 * If this EC contains a volatile expression, then generating child
@@ -3086,12 +3082,8 @@ add_child_join_rel_equivalences(PlannerInfo *root,
 			if (cur_em->em_is_const)
 				continue;		/* ignore consts here */
 
-			/*
-			 * We consider only original EC members here, not
-			 * already-transformed child members.
-			 */
-			Assert(!cur_em->em_is_child);	/* Child members should not exist
-											 * in ec_members */
+			/* Child members should not exist in ec_members */
+			Assert(!cur_em->em_is_child);
 
 			/*
 			 * We may ignore expressions that reference a single baserel,
@@ -3159,7 +3151,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
-					 * EquivalenceAllMemberIterator. Since the iterator needs
+					 * EquivalenceMemberIterator. Since the iterator needs
 					 * EquivalenceMembers whose em_relids has child relations,
 					 * skipping the update of this inverted index allows for
 					 * faster iteration.
@@ -3266,8 +3258,8 @@ add_setop_child_rel_equivalences(PlannerInfo *root, RelOptInfo *child_rel,
 }
 
 /*
- * setup_eclass_all_member_iterator_for_relids
- *	  Setup an EquivalenceAllMemberIterator 'it' to iterate over all parent
+ * setup_eclass_member_iterator_with_children
+ *	  Setup an EquivalenceMemberIterator 'it' to iterate over all parent
  *	  EquivalenceMembers and child members associated with the given 'ec' that
  *	  are relevant to the specified 'relids'.
  *
@@ -3280,7 +3272,7 @@ add_setop_child_rel_equivalences(PlannerInfo *root, RelOptInfo *child_rel,
  *	  em_relids is not a subset. So the caller must check that they satisfy
  *	  the desired condition.
  *	- Once used, the caller should dispose of the iterator by calling
- *	  dispose_eclass_all_member_iterator_for_relids().
+ *	  dispose_eclass_member_iterator().
  *
  * Parameters:
  *	root - The PlannerInfo context.
@@ -3288,10 +3280,10 @@ add_setop_child_rel_equivalences(PlannerInfo *root, RelOptInfo *child_rel,
  *	relids - The Relids used to filter for relevant child members.
  */
 void
-setup_eclass_all_member_iterator_for_relids(EquivalenceAllMemberIterator *it,
-											PlannerInfo *root,
-											EquivalenceClass *ec,
-											Relids relids)
+setup_eclass_member_iterator_with_children(EquivalenceMemberIterator *it,
+										   PlannerInfo *root,
+										   EquivalenceClass *ec,
+										   Relids relids)
 {
 	Bitmapset  *matching_indexes;
 	int			i;
@@ -3300,7 +3292,7 @@ setup_eclass_all_member_iterator_for_relids(EquivalenceAllMemberIterator *it,
 	 * Initialize the iterator.
 	 */
 	it->index = -1;
-	it->modified = false;
+	it->list_is_copy = false;
 	it->ec_members = ec->ec_members;
 
 	/*
@@ -3321,13 +3313,13 @@ setup_eclass_all_member_iterator_for_relids(EquivalenceAllMemberIterator *it,
 	 * 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.
+	 * whose em_relids is a subset of the given '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 '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
@@ -3416,10 +3408,10 @@ setup_eclass_all_member_iterator_for_relids(EquivalenceAllMemberIterator *it,
  *	  the iterator from RelOptInfo.
  *
  * This function is expected to be called only from
- * setup_eclass_all_member_iterator_for_relids().
+ * setup_eclass_member_iterator_with_children().
  */
 static void
-add_eclass_child_members_to_iterator(EquivalenceAllMemberIterator *it,
+add_eclass_child_members_to_iterator(EquivalenceMemberIterator *it,
 									 PlannerInfo *root,
 									 EquivalenceClass *ec,
 									 RelOptInfo *child_rel)
@@ -3438,10 +3430,10 @@ add_eclass_child_members_to_iterator(EquivalenceAllMemberIterator *it,
 		 * If this is the first time the iterator's list has been modified, we
 		 * need to make a copy of it.
 		 */
-		if (!it->modified)
+		if (!it->list_is_copy)
 		{
 			it->ec_members = list_copy(it->ec_members);
-			it->modified = true;
+			it->list_is_copy = true;
 		}
 
 		/* Add this child EquivalenceMember to the list */
@@ -3450,13 +3442,13 @@ add_eclass_child_members_to_iterator(EquivalenceAllMemberIterator *it,
 }
 
 /*
- * eclass_all_member_iterator_for_relids_next
- *	  Get a next EquivalenceMember from an EquivalenceAllMemberIterator 'it'
- *	  that was setup by setup_eclass_all_member_iterator_for_relids(). NULL is
+ * eclass_member_iterator_next
+ *	  Get a next EquivalenceMember from an EquivalenceMemberIterator 'it'
+ *	  that was setup by setup_eclass_member_iterator_with_children(). NULL is
  *	  returned if there are no members left.
  */
 EquivalenceMember *
-eclass_all_member_iterator_for_relids_next(EquivalenceAllMemberIterator *it)
+eclass_member_iterator_next(EquivalenceMemberIterator *it)
 {
 	if (++it->index < list_length(it->ec_members))
 		return list_nth_node(EquivalenceMember, it->ec_members, it->index);
@@ -3464,17 +3456,17 @@ eclass_all_member_iterator_for_relids_next(EquivalenceAllMemberIterator *it)
 }
 
 /*
- * dispose_eclass_all_member_iterator_for_relids
+ * dispose_eclass_member_iterator
  *	  Free any memory allocated by the iterator.
  */
 void
-dispose_eclass_all_member_iterator_for_relids(EquivalenceAllMemberIterator *it)
+dispose_eclass_member_iterator(EquivalenceMemberIterator *it)
 {
 	/*
 	 * XXX Should we use list_free()? I decided to use this style to take
 	 * advantage of speculative execution.
 	 */
-	if (unlikely(it->modified))
+	if (unlikely(it->list_is_copy))
 		pfree(it->ec_members);
 }
 
@@ -3532,7 +3524,7 @@ generate_implied_equalities_for_column(PlannerInfo *root,
 		EquivalenceClass *cur_ec = (EquivalenceClass *) list_nth(root->eq_classes, i);
 		EquivalenceMember *cur_em;
 		ListCell   *lc2;
-		EquivalenceAllMemberIterator it;
+		EquivalenceMemberIterator it;
 
 		/* Sanity check eclass_indexes only contain ECs for rel */
 		Assert(is_child_rel || bms_is_subset(rel->relids, cur_ec->ec_relids));
@@ -3554,14 +3546,14 @@ generate_implied_equalities_for_column(PlannerInfo *root,
 		 * corner cases, so for now we live with just reporting the first
 		 * match.  See also get_eclass_for_sort_expr.)
 		 */
-		setup_eclass_all_member_iterator_for_relids(&it, root, cur_ec, rel->relids);
-		while ((cur_em = eclass_all_member_iterator_for_relids_next(&it)) != NULL)
+		setup_eclass_member_iterator_with_children(&it, root, cur_ec, rel->relids);
+		while ((cur_em = eclass_member_iterator_next(&it)) != NULL)
 		{
 			if (bms_equal(cur_em->em_relids, rel->relids) &&
 				callback(root, rel, cur_ec, cur_em, callback_arg))
 				break;
 		}
-		dispose_eclass_all_member_iterator_for_relids(&it);
+		dispose_eclass_member_iterator(&it);
 
 		if (!cur_em)
 			continue;
diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c
index 38f7322caf9..c206f260633 100644
--- a/src/backend/optimizer/path/indxpath.c
+++ b/src/backend/optimizer/path/indxpath.c
@@ -3756,7 +3756,7 @@ match_pathkeys_to_index(PlannerInfo *root, IndexOptInfo *index, List *pathkeys,
 	{
 		PathKey    *pathkey = (PathKey *) lfirst(lc1);
 		bool		found = false;
-		EquivalenceAllMemberIterator it;
+		EquivalenceMemberIterator it;
 		EquivalenceMember *member;
 
 
@@ -3777,9 +3777,9 @@ match_pathkeys_to_index(PlannerInfo *root, IndexOptInfo *index, List *pathkeys,
 		 * be considered to match more than one pathkey list, which is OK
 		 * here.  See also get_eclass_for_sort_expr.)
 		 */
-		setup_eclass_all_member_iterator_for_relids(&it, root, pathkey->pk_eclass,
-													index->rel->relids);
-		while ((member = eclass_all_member_iterator_for_relids_next(&it)) != NULL)
+		setup_eclass_member_iterator_with_children(&it, root, pathkey->pk_eclass,
+												   index->rel->relids);
+		while ((member = eclass_member_iterator_next(&it)) != NULL)
 		{
 			int			indexcol;
 
@@ -3815,7 +3815,7 @@ match_pathkeys_to_index(PlannerInfo *root, IndexOptInfo *index, List *pathkeys,
 			if (found)			/* don't want to look at remaining members */
 				break;
 		}
-		dispose_eclass_all_member_iterator_for_relids(&it);
+		dispose_eclass_member_iterator(&it);
 
 		/*
 		 * Return the matches found so far when this pathkey couldn't be
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index eff5d93aa3a..163923072df 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -6201,6 +6201,7 @@ make_incrementalsort(Plan *lefttree, int numCols, int nPresortedCols,
  * adjusts the plan targetlist if needed to add resjunk sort columns.
  *
  * Input parameters:
+ *	  'root' is the PlannerInfo context
  *	  'lefttree' is the plan node which yields input tuples
  *	  'pathkeys' is the list of pathkeys by which the result is to be sorted
  *	  'relids' identifies the child relation being sorted, if any
@@ -6411,6 +6412,7 @@ prepare_sort_from_pathkeys(PlannerInfo *root, Plan *lefttree, List *pathkeys,
  * make_sort_from_pathkeys
  *	  Create sort plan to sort according to given pathkeys
  *
+ *	  'root' is the PlannerInfo context
  *	  'lefttree' is the node which yields input tuples
  *	  'pathkeys' is the list of pathkeys by which the result is to be sorted
  *	  'relids' is the set of relations required by prepare_sort_from_pathkeys()
@@ -6446,6 +6448,7 @@ make_sort_from_pathkeys(PlannerInfo *root, Plan *lefttree, List *pathkeys,
  * make_incrementalsort_from_pathkeys
  *	  Create sort plan to sort according to given pathkeys
  *
+ *	  'root' is the PlannerInfo context
  *	  'lefttree' is the node which yields input tuples
  *	  'pathkeys' is the list of pathkeys by which the result is to be sorted
  *	  'relids' is the set of relations required by prepare_sort_from_pathkeys()
diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c
index 8dc51353791..aa37dda82b8 100644
--- a/src/backend/optimizer/util/relnode.c
+++ b/src/backend/optimizer/util/relnode.c
@@ -119,6 +119,11 @@ setup_simple_rel_arrays(PlannerInfo *root)
 		root->simple_rte_array[rti++] = rte;
 	}
 
+	/*
+	 * eclass_indexes_array is always needed, even if there are no
+	 * AppendRelInfos, because it stores indexes for RestrictInfos on base
+	 * rels.
+	 */
 	root->eclass_indexes_array = (EquivalenceClassIndexes *)
 		palloc0(size * sizeof(EquivalenceClassIndexes));
 
@@ -240,6 +245,7 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptInfo *parent)
 	rel->subplan_params = NIL;
 	rel->rel_parallel_workers = -1; /* set up in get_relation_info */
 	rel->amflags = 0;
+	rel->join_rel_list_index = -1;
 	rel->eclass_child_members = NIL;
 	rel->serverid = InvalidOid;
 	if (rte->rtekind == RTE_RELATION)
@@ -633,14 +639,14 @@ set_foreign_rel_properties(RelOptInfo *joinrel, RelOptInfo *outer_rel,
 static void
 add_join_rel(PlannerInfo *root, RelOptInfo *joinrel)
 {
-	/* GEQO requires us to append the new joinrel to the end of the list! */
-	root->join_rel_list = lappend(root->join_rel_list, joinrel);
-
 	/*
 	 * Store the index of this joinrel to use in
 	 * add_child_join_rel_equivalences().
 	 */
-	joinrel->join_rel_list_index = list_length(root->join_rel_list) - 1;
+	joinrel->join_rel_list_index = list_length(root->join_rel_list);
+
+	/* GEQO requires us to append the new joinrel to the end of the list! */
+	root->join_rel_list = lappend(root->join_rel_list, joinrel);
 
 	/* store it into the auxiliary hashtable if there is one. */
 	if (root->join_rel_hash)
@@ -754,6 +760,7 @@ build_join_rel(PlannerInfo *root,
 	joinrel->subplan_params = NIL;
 	joinrel->rel_parallel_workers = -1;
 	joinrel->amflags = 0;
+	joinrel->join_rel_list_index = -1;
 	joinrel->eclass_child_members = NIL;
 	joinrel->serverid = InvalidOid;
 	joinrel->userid = InvalidOid;
@@ -942,6 +949,7 @@ build_child_join_rel(PlannerInfo *root, RelOptInfo *outer_rel,
 	joinrel->subroot = NULL;
 	joinrel->subplan_params = NIL;
 	joinrel->amflags = 0;
+	joinrel->join_rel_list_index = -1;
 	joinrel->eclass_child_members = NIL;
 	joinrel->serverid = InvalidOid;
 	joinrel->userid = InvalidOid;
@@ -1505,7 +1513,8 @@ fetch_upper_rel(PlannerInfo *root, UpperRelationKind kind, Relids relids)
 	upperrel->cheapest_total_path = NULL;
 	upperrel->cheapest_unique_path = NULL;
 	upperrel->cheapest_parameterized_paths = NIL;
-	upperrel->eclass_child_members = NIL;	/* XXX Is this required? */
+	upperrel->join_rel_list_index = -1;
+	upperrel->eclass_child_members = NIL;
 
 	root->upper_rels[kind] = lappend(root->upper_rels[kind], upperrel);
 
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index 899165b20d8..c7cf1328d7a 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -276,8 +276,8 @@ struct PlannerInfo
 
 	/*
 	 * eclass_indexes_array is the same length as simple_rel_array and holds
-	 * the indexes of the corresponding rels for faster lookups of
-	 * RestrictInfo. See the EquivalenceClass comment for more details.
+	 * the indexes of the corresponding rels for faster EquivalenceMember
+	 * lookups. See the EquivalenceClass comment for more details.
 	 */
 	struct EquivalenceClassIndexes *eclass_indexes_array pg_node_attr(read_write_ignore);
 
@@ -1003,7 +1003,7 @@ typedef struct RelOptInfo
 	 * information about a join rel
 	 */
 	/* index in root->join_rel_list of this rel */
-	Index		join_rel_list_index;
+	int			join_rel_list_index;
 
 	/*
 	 * EquivalenceMembers referencing this rel
@@ -1431,9 +1431,9 @@ typedef struct JoinDomain
  *
  * EquivalenceClass->ec_members can only have parent members, and child members
  * are stored in RelOptInfos, from which those child members are translated. To
- * lookup child EquivalenceMembers, we use EquivalenceAllMemberIterator. See
+ * lookup child EquivalenceMembers, we use EquivalenceMemberIterator. See
  * its comment for usage. The approach to lookup child members quickly is
- * described as setup_eclass_all_member_iterator_for_relids() comment.
+ * described as setup_eclass_member_iterator_with_children() comment.
  *
  * At various locations in the query planner, we must search for source and
  * derived RestrictInfos regarding a given EquivalenceClass.  For the common
@@ -1533,9 +1533,9 @@ typedef struct EquivalenceMember
 } EquivalenceMember;
 
 /*
- * EquivalenceAllMemberIterator
+ * EquivalenceMemberIterator
  *
- * EquivalenceAllMemberIterator is designed to iterate over all parent
+ * EquivalenceMemberIterator is designed to iterate over all parent
  * EquivalenceMembers and child members associated with the given 'ec' that
  * are relevant to the specified 'relids'. In particular, it iterates over:
  *	- All parent members stored directly in ec->ec_members.
@@ -1551,23 +1551,23 @@ typedef struct EquivalenceMember
  * PlannerInfo					   *root = given;
  * EquivalenceClass				   *ec = given;
  * Relids							rel = given;
- * EquivalenceAllMemberIterator		it;
+ * EquivalenceMemberIterator		it;
  * EquivalenceMember			   *em;
  *
- * setup_eclass_all_member_iterator_for_relids(&it, root, ec, rel);
- * while ((em = eclass_all_member_iterator_for_relids_next(&it)) != NULL)
+ * setup_eclass_member_iterator_with_children(&it, root, ec, rel);
+ * while ((em = eclass_member_iterator_next(&it)) != NULL)
  * {
  *     use em ...;
  * }
- * dispose_eclass_all_member_iterator_for_relids(&it);
+ * dispose_eclass_member_iterator(&it);
  * -----
  */
 typedef struct
 {
 	int			index;			/* current index within 'ec_members'. */
-	bool		modified;		/* is 'ec_members' a newly allocated one? */
+	bool		list_is_copy;	/* is 'ec_members' a newly allocated one? */
 	List	   *ec_members;		/* parent and child members */
-} EquivalenceAllMemberIterator;
+} EquivalenceMemberIterator;
 
 /*
  * RestrictInfoIterator
diff --git a/src/include/optimizer/paths.h b/src/include/optimizer/paths.h
index e8706b2774c..13c739965ba 100644
--- a/src/include/optimizer/paths.h
+++ b/src/include/optimizer/paths.h
@@ -185,12 +185,12 @@ extern void add_setop_child_rel_equivalences(PlannerInfo *root,
 											 RelOptInfo *child_rel,
 											 List *child_tlist,
 											 List *setop_pathkeys);
-extern void setup_eclass_all_member_iterator_for_relids(EquivalenceAllMemberIterator *it,
-														PlannerInfo *root,
-														EquivalenceClass *ec,
-														Relids relids);
-extern EquivalenceMember *eclass_all_member_iterator_for_relids_next(EquivalenceAllMemberIterator *it);
-extern void dispose_eclass_all_member_iterator_for_relids(EquivalenceAllMemberIterator *it);
+extern void setup_eclass_member_iterator_with_children(EquivalenceMemberIterator *it,
+													   PlannerInfo *root,
+													   EquivalenceClass *ec,
+													   Relids relids);
+extern EquivalenceMember *eclass_member_iterator_next(EquivalenceMemberIterator *it);
+extern void dispose_eclass_member_iterator(EquivalenceMemberIterator *it);
 extern List *generate_implied_equalities_for_column(PlannerInfo *root,
 													RelOptInfo *rel,
 													ec_matches_callback_type callback,
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 85b330df4dd..d2fc11ae19c 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -699,10 +699,10 @@ EphemeralNamedRelation
 EphemeralNamedRelationData
 EphemeralNamedRelationMetadata
 EphemeralNamedRelationMetadataData
-EquivalenceAllMemberIterator
 EquivalenceClass
 EquivalenceClassIndexes
 EquivalenceMember
+EquivalenceMemberIterator
 ErrorContextCallback
 ErrorData
 ErrorSaveContext