summaryrefslogtreecommitdiff
path: root/src/backend/optimizer/plan
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2023-02-20 15:18:22 -0500
committerTom Lane <tgl@sss.pgh.pa.us>2023-02-20 15:18:32 -0500
commitf6db76c55509a60cc8c22ced56ff9322ee6f1742 (patch)
tree301c56dbdd4a81b37cb06d56a74f55bff82c8649 /src/backend/optimizer/plan
parent69e8c7cf1dfa08ae099c33d0d371ad69d405903d (diff)
downloadpostgresql-f6db76c55509a60cc8c22ced56ff9322ee6f1742.tar.gz
Prevent join removal from removing the query's result relation.
This was not something that required consideration before MERGE was invented; but MERGE builds a join tree that left-joins to the result relation, meaning that remove_useless_joins will consider removing it. That should generally be stopped by the query's use of output variables from the result relation. However, if the result relation is inherited (e.g. a partitioned table) then we don't add any row identity variables to the query until expand_inherited_rtentry, which happens after join removal. This was exposed as of commit 3c569049b, which made it possible to deduce that a partitioned table could contain at most one row matching a join key, enabling removal of the not-yet-expanded result relation. Ooops. To fix, let's just teach join_is_removable that the query result rel is never removable. It's a cheap enough test in any case, and it'll save some cycles that we'd otherwise expend in proving that it's not removable, even in the cases we got right. Back-patch to v15 where MERGE was added. Although I think the case cannot be reached in v15, this seems like cheap insurance. Per investigation of a report from Alexander Lakhin. Discussion: https://postgr.es/m/36bee393-b351-16ac-93b2-d46d83637e45@gmail.com
Diffstat (limited to 'src/backend/optimizer/plan')
-rw-r--r--src/backend/optimizer/plan/analyzejoins.c8
1 files changed, 8 insertions, 0 deletions
diff --git a/src/backend/optimizer/plan/analyzejoins.c b/src/backend/optimizer/plan/analyzejoins.c
index 0dfefd71f2..f79bc4430c 100644
--- a/src/backend/optimizer/plan/analyzejoins.c
+++ b/src/backend/optimizer/plan/analyzejoins.c
@@ -183,6 +183,14 @@ join_is_removable(PlannerInfo *root, SpecialJoinInfo *sjinfo)
if (!bms_get_singleton_member(sjinfo->min_righthand, &innerrelid))
return false;
+ /*
+ * Never try to eliminate a left join to the query result rel. Although
+ * the case is syntactically impossible in standard SQL, MERGE will build
+ * a join tree that looks exactly like that.
+ */
+ if (innerrelid == root->parse->resultRelation)
+ return false;
+
innerrel = find_base_rel(root, innerrelid);
/*