mirror of
https://github.com/postgres/postgres.git
synced 2025-07-07 00:36:50 +03:00
Fix EquivalenceClass processing for nested append relations.
The original coding of EquivalenceClasses didn't foresee that appendrel child relations might themselves be appendrels; but this is possible for example when a UNION ALL subquery scans a table with inheritance children. The oversight led to failure to optimize ordering-related issues very well for the grandchild tables. After some false starts involving explicitly flattening the appendrel representation, we found that this could be fixed easily by removing a few implicit assumptions about appendrel parent rels not being children themselves. Kyotaro Horiguchi and Tom Lane, reviewed by Noah Misch
This commit is contained in:
@ -1021,10 +1021,15 @@ get_cheapest_parameterized_child_path(PlannerInfo *root, RelOptInfo *rel,
|
||||
* accumulate_append_subpath
|
||||
* Add a subpath to the list being built for an Append or MergeAppend
|
||||
*
|
||||
* It's possible that the child is itself an Append path, in which case
|
||||
* we can "cut out the middleman" and just add its child paths to our
|
||||
* own list. (We don't try to do this earlier because we need to
|
||||
* apply both levels of transformation to the quals.)
|
||||
* It's possible that the child is itself an Append or MergeAppend path, in
|
||||
* which case we can "cut out the middleman" and just add its child paths to
|
||||
* our own list. (We don't try to do this earlier because we need to apply
|
||||
* both levels of transformation to the quals.)
|
||||
*
|
||||
* Note that if we omit a child MergeAppend in this way, we are effectively
|
||||
* omitting a sort step, which seems fine: if the parent is to be an Append,
|
||||
* its result would be unsorted anyway, while if the parent is to be a
|
||||
* MergeAppend, there's no point in a separate sort on a child.
|
||||
*/
|
||||
static List *
|
||||
accumulate_append_subpath(List *subpaths, Path *path)
|
||||
@ -1036,6 +1041,13 @@ accumulate_append_subpath(List *subpaths, Path *path)
|
||||
/* list_copy is important here to avoid sharing list substructure */
|
||||
return list_concat(subpaths, list_copy(apath->subpaths));
|
||||
}
|
||||
else if (IsA(path, MergeAppendPath))
|
||||
{
|
||||
MergeAppendPath *mpath = (MergeAppendPath *) path;
|
||||
|
||||
/* list_copy is important here to avoid sharing list substructure */
|
||||
return list_concat(subpaths, list_copy(mpath->subpaths));
|
||||
}
|
||||
else
|
||||
return lappend(subpaths, path);
|
||||
}
|
||||
|
@ -1937,16 +1937,20 @@ add_child_rel_equivalences(PlannerInfo *root,
|
||||
if (cur_ec->ec_has_volatile)
|
||||
continue;
|
||||
|
||||
/* No point in searching if parent rel not mentioned in eclass */
|
||||
if (!bms_is_subset(parent_rel->relids, cur_ec->ec_relids))
|
||||
/*
|
||||
* No point in searching if parent rel not mentioned in eclass; but
|
||||
* we can't tell that for sure if parent rel is itself a child.
|
||||
*/
|
||||
if (parent_rel->reloptkind == RELOPT_BASEREL &&
|
||||
!bms_is_subset(parent_rel->relids, cur_ec->ec_relids))
|
||||
continue;
|
||||
|
||||
foreach(lc2, cur_ec->ec_members)
|
||||
{
|
||||
EquivalenceMember *cur_em = (EquivalenceMember *) lfirst(lc2);
|
||||
|
||||
if (cur_em->em_is_const || cur_em->em_is_child)
|
||||
continue; /* ignore consts and children here */
|
||||
if (cur_em->em_is_const)
|
||||
continue; /* ignore consts here */
|
||||
|
||||
/* Does it reference parent_rel? */
|
||||
if (bms_overlap(cur_em->em_relids, parent_rel->relids))
|
||||
|
Reference in New Issue
Block a user