mirror of
https://github.com/postgres/postgres.git
synced 2025-07-30 11:03:19 +03:00
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
This commit is contained in:
@ -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);
|
||||
|
||||
/*
|
||||
|
Reference in New Issue
Block a user