From c6df0d6e55b3aed79ffd23670656a991e8a243c9 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Tue, 16 May 2023 19:33:01 -0400 Subject: [PATCH v6 3/5] Examine the transitive closure in add_outer_joins_to_relids. We also have to check outer joins that commute with commutators of the one we just completed. Richard Guo Discussion: https://postgr.es/m/0b819232-4b50-f245-1c7d-c8c61bf41827@postgrespro.ru --- src/backend/optimizer/path/joinrels.c | 29 +++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/src/backend/optimizer/path/joinrels.c b/src/backend/optimizer/path/joinrels.c index 262d3aec65..e8beaca196 100644 --- a/src/backend/optimizer/path/joinrels.c +++ b/src/backend/optimizer/path/joinrels.c @@ -804,12 +804,17 @@ add_outer_joins_to_relids(PlannerInfo *root, Relids input_relids, return bms_add_member(input_relids, sjinfo->ojrelid); /* - * Add the OJ relid unless this join has been pushed into the RHS of a - * syntactically-lower left join per OJ identity 3. (If it has, then we + * We cannot add the OJ relid if this join has been pushed into the RHS of + * a syntactically-lower left join per OJ identity 3. (If it has, then we * cannot claim that its outputs represent the final state of its RHS.) + * There will not be any higher OJs that can be added either, so we're + * done. */ - if (bms_is_subset(sjinfo->commute_below_l, input_relids)) - input_relids = bms_add_member(input_relids, sjinfo->ojrelid); + if (!bms_is_subset(sjinfo->commute_below_l, input_relids)) + return input_relids; + + /* OK to add OJ's own relid */ + input_relids = bms_add_member(input_relids, sjinfo->ojrelid); /* * Contrariwise, if we are now forming the final result of such a commuted @@ -818,6 +823,7 @@ add_outer_joins_to_relids(PlannerInfo *root, Relids input_relids, */ if (sjinfo->commute_above_l) { + Relids commute_above_rels = bms_copy(sjinfo->commute_above_l); ListCell *lc; /* @@ -835,15 +841,26 @@ add_outer_joins_to_relids(PlannerInfo *root, Relids input_relids, othersj->ojrelid == 0 || othersj->jointype != JOIN_LEFT) continue; /* definitely not interesting */ - if (othersj->commute_below_l == NULL) - continue; /* was never a candidate to be pushed down */ + if (!bms_is_member(othersj->ojrelid, commute_above_rels)) + continue; /* Add it if not already present but conditions now satisfied */ if (!bms_is_member(othersj->ojrelid, input_relids) && bms_is_subset(othersj->min_lefthand, input_relids) && bms_is_subset(othersj->min_righthand, input_relids) && bms_is_subset(othersj->commute_below_l, input_relids)) + { input_relids = bms_add_member(input_relids, othersj->ojrelid); + + /* + * We must also check any joins that othersj potentially + * commutes with. They likewise must appear later in + * join_info_list than othersj itself, so we can visit them + * later in this loop. + */ + commute_above_rels = bms_add_members(commute_above_rels, + othersj->commute_above_l); + } } } -- 2.31.1