From: Robert Haas Date: Thu, 11 Dec 2025 20:37:56 +0000 (-0500) Subject: Prune the list of non-unique semijoins. X-Git-Url: http://git.postgresql.org/gitweb/?a=commitdiff_plain;h=refs%2Fheads%2Fpgpa_semijoin;p=users%2Frhaas%2Fpostgres.git Prune the list of non-unique semijoins. Test the list of unique semijoins. This causes a bunch of breakage, all of which I believe to be due to eager aggregation. --- diff --git a/contrib/pg_plan_advice/pgpa_walker.c b/contrib/pg_plan_advice/pgpa_walker.c index d5493bc0b8..318fddc9e3 100644 --- a/contrib/pg_plan_advice/pgpa_walker.c +++ b/contrib/pg_plan_advice/pgpa_walker.c @@ -72,6 +72,8 @@ pgpa_plan_walker(pgpa_plan_walker_context *walker, PlannedStmt *pstmt, List *sj_unique_rels) { ListCell *lc; + List *sj_unique_rtis = NULL; + List *sj_nonunique_qfs = NULL; /* Initialization. */ memset(walker, 0, sizeof(pgpa_plan_walker_context)); @@ -88,6 +90,75 @@ pgpa_plan_walker(pgpa_plan_walker_context *walker, PlannedStmt *pstmt, if (plan != NULL) pgpa_walk_recursively(walker, plan, 0, NULL, NIL, false); } + + /* Adjust RTIs from sj_unique_rels for the flattened range table. */ + foreach_ptr(pgpa_sj_unique_rel, ur, sj_unique_rels) + { + int rtindex = -1; + int rtoffset = 0; + bool dummy = false; + Bitmapset *relids = NULL; + + /* If this is a subplan, find the range table offset. */ + if (ur->plan_name != NULL) + { + foreach_node(SubPlanRTInfo, rtinfo, pstmt->subrtinfos) + { + if (strcmp(ur->plan_name, rtinfo->plan_name) == 0) + { + rtoffset = rtinfo->rtoffset; + dummy = rtinfo->dummy; + break; + } + } + + if (rtoffset == 0) + elog(ERROR, "no rtoffset for plan %s", ur->plan_name); + } + + /* If this entry pertains to a dummy subquery, ignore it. */ + if (dummy) + continue; + + /* Offset each entry from the original set. */ + while ((rtindex = bms_next_member(ur->relids, rtindex)) >= 0) + relids = bms_add_member(relids, rtindex + rtoffset); + + /* Store the resulting set. */ + sj_unique_rtis = lappend(sj_unique_rtis, relids); + } + + /* + * Remove any non-unique semjoin query features for which making the + * rel unique wasn't considered. + */ + foreach_ptr(pgpa_query_feature, qf, + walker->query_features[PGPAQF_SEMIJOIN_NON_UNIQUE]) + { + if (list_member(sj_unique_rtis, qf->relids)) + sj_nonunique_qfs = lappend(sj_nonunique_qfs, qf); + } + walker->query_features[PGPAQF_SEMIJOIN_NON_UNIQUE] = sj_nonunique_qfs; + + /* + * If we find any cases where analysis of the Plan tree shows that the + * semijoin was made unique but this possibility was never observed to + * be considered during planning, then we have a bug somewhere. + */ + foreach_ptr(pgpa_query_feature, qf, + walker->query_features[PGPAQF_SEMIJOIN_UNIQUE]) + { + if (!list_member(sj_unique_rtis, qf->relids)) + { + StringInfoData buf; + + initStringInfo(&buf); + outBitmapset(&buf, qf->relids); + elog(ERROR, + "unique semijoin found for relids %s but not observed during planning", + buf.data); + } + } } /*