From 2de0de6020be4d757db2ed10ff4f57f77fbd5520 Mon Sep 17 00:00:00 2001 From: Yuya Watari Date: Fri, 27 Jan 2023 11:26:13 +0900 Subject: [PATCH v12 4/4] 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