From 40fe5da785c3fe11ba561d27873151ef0b0737f6 Mon Sep 17 00:00:00 2001
From: Yuya Watari <watari.yuya@gmail.com>
Date: Fri, 27 Jan 2023 11:26:13 +0900
Subject: [PATCH v13 4/7] Add a validation to check that two iteration results
 are the same

---
 src/backend/optimizer/path/equivclass.c | 92 +++++++++++++++++++++++++
 1 file changed, 92 insertions(+)

diff --git a/src/backend/optimizer/path/equivclass.c b/src/backend/optimizer/path/equivclass.c
index bd9493f659..561f50cafa 100644
--- a/src/backend/optimizer/path/equivclass.c
+++ b/src/backend/optimizer/path/equivclass.c
@@ -3550,6 +3550,68 @@ get_ecmember_indexes_strict(PlannerInfo *root, EquivalenceClass *ec,
  */
 #define ECMEMBER_INDEX_THRESHOLD 16
 
+#ifdef USE_ASSERT_CHECKING
+static int
+list_ptr_cmp(const ListCell *p1, const ListCell *p2)
+{
+	void   *v1 = lfirst(p1);
+	void   *v2 = lfirst(p2);
+
+	if (v1 < v2)
+		return -1;
+	if (v1 > v2)
+		return 1;
+	return 0;
+}
+
+/*
+ * validate_eclass_member_iterator
+ *		Assert that the results of the iterations are the same with and without
+ *		indexes. The function iterates in two methods and asserts that the
+ *		results are equal.
+ */
+static void
+validate_eclass_member_iterator(const EquivalenceMemberIterator *iter,
+								EquivalenceMember *(*next)(EquivalenceMemberIterator *iter))
+{
+	/* First, we create two copies of the given iterator */
+	EquivalenceMemberIterator	with_index = *iter;
+	EquivalenceMemberIterator	without_index = *iter;
+
+	/* The results of the two iterations */
+	List					   *result_with_index = NIL;
+	List					   *result_without_index = NIL;
+
+	EquivalenceMember		   *em;
+	ListCell				   *lc1;
+	ListCell				   *lc2;
+
+	/* Set flags */
+	with_index.use_index = true;
+	without_index.use_index = false;
+
+	/* Get the result with index */
+	while ((em = next(&with_index)) != NULL)
+		result_with_index = lappend(result_with_index, em);
+
+	/* Get the result without index */
+	while ((em = next(&without_index)) != NULL)
+		result_without_index = lappend(result_without_index, em);
+
+	/* Sort the two lists to ignore the iteration order */
+	list_sort(result_with_index, list_ptr_cmp);
+	list_sort(result_without_index, list_ptr_cmp);
+
+	/* Validate */
+	Assert(list_length(result_with_index) == list_length(result_without_index));
+
+	forboth(lc1, result_with_index, lc2, result_without_index)
+	{
+		Assert(lfirst(lc1) == lfirst(lc2));
+	}
+}
+#endif
+
 /*
  * setup_eclass_member_iterator
  *		Setup 'iter' so it's ready for eclass_member_iterator_next to start
@@ -3572,14 +3634,29 @@ setup_eclass_member_iterator(EquivalenceMemberIterator *iter,
 	iter->root = root;
 	iter->eclass = ec;
 
+#ifdef USE_ASSERT_CHECKING
+	/*
+	 * When assert checking is enabled, we always create indexes to check the
+	 * result of the iteration in validate_eclass_member_iterator().
+	 */
+	iter->matching_ems = get_ecmember_indexes(root, ec, relids,
+											  with_children,
+											  with_norel_members);
+#else
 	if (iter->use_index)
 		iter->matching_ems = get_ecmember_indexes(root, ec, relids,
 												  with_children,
 												  with_norel_members);
 	else
 		iter->matching_ems = NULL;
+#endif
 
 	iter->current_index = -1;
+
+#ifdef USE_ASSERT_CHECKING
+	/* Assert that the results are the same with and without indexes */
+	validate_eclass_member_iterator(iter, eclass_member_iterator_next);
+#endif
 }
 
 /*
@@ -3605,14 +3682,29 @@ setup_eclass_member_strict_iterator(EquivalenceMemberIterator *iter,
 	iter->root = root;
 	iter->eclass = ec;
 
+#ifdef USE_ASSERT_CHECKING
+	/*
+	 * When assert checking is enabled, we always create indexes to check the
+	 * result of the iteration in validate_eclass_member_iterator().
+	 */
+	iter->matching_ems = get_ecmember_indexes_strict(root, ec, relids,
+													 with_children,
+													 with_norel_members);
+#else
 	if (iter->use_index)
 		iter->matching_ems = get_ecmember_indexes_strict(root, ec, relids,
 														 with_children,
 														 with_norel_members);
 	else
 		iter->matching_ems = NULL;
+#endif
 
 	iter->current_index = -1;
+
+#ifdef USE_ASSERT_CHECKING
+	/* Assert that the results are the same with and without indexes */
+	validate_eclass_member_iterator(iter, eclass_member_iterator_strict_next);
+#endif
 }
 
 /*
-- 
2.35.3.windows.1

