eq_member_find_duplicates.patch.txt
text/plain
Filename: eq_member_find_duplicates.patch.txt
Type: text/plain
Part: 0
diff --git b/src/backend/optimizer/path/equivclass.c a/src/backend/optimizer/path/equivclass.c
index b8c64d80987..30f1ca37e2e 100644
--- b/src/backend/optimizer/path/equivclass.c
+++ a/src/backend/optimizer/path/equivclass.c
@@ -617,6 +617,7 @@ make_eq_member(EquivalenceClass *ec, Expr *expr, Relids relids,
ec->ec_has_const = true;
/* it can't affect ec_relids */
}
+ em->iterator_generation = 0;
return em;
}
@@ -930,6 +931,7 @@ find_ec_member_matching_expr(EquivalenceClass *ec,
expr = ((RelabelType *) expr)->arg;
setup_eclass_member_iterator(&it, ec, relids);
+ it.warn_if_returned_before = false;
while ((em = eclass_member_iterator_next(&it)) != NULL)
{
Expr *emexpr;
@@ -3149,10 +3151,14 @@ add_setop_child_rel_equivalences(PlannerInfo *root, RelOptInfo *child_rel,
* ec - The EquivalenceClass from which to iterate members.
* child_relids - The relids to return child members for.
*/
+uint64 iterator_generation = 0;
+
void
setup_eclass_member_iterator(EquivalenceMemberIterator *it,
EquivalenceClass *ec, Relids child_relids)
{
+ it->iterator_generation = ++iterator_generation;
+ it->warn_if_returned_before = true;
it->ec = ec;
/* no need to set this if the class has no child members */
it->child_relids = ec->ec_childmembers != NULL ? child_relids : NULL;
@@ -3179,6 +3185,9 @@ nextcell:
EquivalenceMember *em;
em = lfirst_node(EquivalenceMember, it->current_cell);
+ if (it->warn_if_returned_before && em->iterator_generation == it->iterator_generation)
+ elog(NOTICE, "returned before %llu", it->iterator_generation);
+ em->iterator_generation = it->iterator_generation;
it->current_cell = lnext(it->current_list, it->current_cell);
return em;
}
diff --git b/src/include/nodes/pathnodes.h a/src/include/nodes/pathnodes.h
index a44f5bb1f60..60f156da136 100644
--- b/src/include/nodes/pathnodes.h
+++ a/src/include/nodes/pathnodes.h
@@ -1514,6 +1514,7 @@ typedef struct EquivalenceMember
JoinDomain *em_jdomain; /* join domain containing the source clause */
/* if em_is_child is true, this links to corresponding EM for top parent */
struct EquivalenceMember *em_parent pg_node_attr(read_write_ignore);
+ uint64 iterator_generation;
} EquivalenceMember;
/*
@@ -1570,6 +1571,8 @@ typedef struct EquivalenceMember
*/
typedef struct
{
+ uint64 iterator_generation;
+ bool warn_if_returned_before;
EquivalenceClass *ec; /* The EquivalenceClass to iterate over */
int current_relid; /* Current relid position within 'relids'. -1
* when still looping over ec_members and -2