mirror of
https://github.com/postgres/postgres.git
synced 2025-07-05 07:21:24 +03:00
Suppress Append and MergeAppend plan nodes that have a single child.
If there's only one child relation, the Append or MergeAppend isn't doing anything useful, and can be elided. It does have a purpose during planning though, which is to serve as a buffer between parent and child Var numbering. Therefore we keep it all the way through to setrefs.c, and get rid of it only after fixing references in the plan level(s) above it. This works largely the same as setrefs.c's ancient hack to get rid of no-op SubqueryScan nodes, and can even share some code with that. Note the change to make setrefs.c use apply_tlist_labeling rather than ad-hoc code. This has the effect of propagating the child's resjunk and ressortgroupref labels, which formerly weren't propagated when removing a SubqueryScan. Doing that is demonstrably necessary for the [Merge]Append cases, and seems harmless for SubqueryScan, if only because trivial_subqueryscan is afraid to collapse cases where the resjunk marking differs. (I suspect that restriction could now be removed, though it's unclear that it'd make any new matches possible, since the outer query can't have references to a child resjunk column.) David Rowley, reviewed by Alvaro Herrera and Tomas Vondra Discussion: https://postgr.es/m/CAKJS1f_7u8ATyJ1JGTMHFoKDvZdeF-iEBhs+sM_SXowOr9cArg@mail.gmail.com
This commit is contained in:
@ -447,6 +447,36 @@ ExecSupportsMarkRestore(Path *pathnode)
|
||||
return false; /* childless Result */
|
||||
}
|
||||
|
||||
case T_Append:
|
||||
{
|
||||
AppendPath *appendPath = castNode(AppendPath, pathnode);
|
||||
|
||||
/*
|
||||
* If there's exactly one child, then there will be no Append
|
||||
* in the final plan, so we can handle mark/restore if the
|
||||
* child plan node can.
|
||||
*/
|
||||
if (list_length(appendPath->subpaths) == 1)
|
||||
return ExecSupportsMarkRestore((Path *) linitial(appendPath->subpaths));
|
||||
/* Otherwise, Append can't handle it */
|
||||
return false;
|
||||
}
|
||||
|
||||
case T_MergeAppend:
|
||||
{
|
||||
MergeAppendPath *mapath = castNode(MergeAppendPath, pathnode);
|
||||
|
||||
/*
|
||||
* Like the Append case above, single-subpath MergeAppends
|
||||
* won't be in the final plan, so just return the child's
|
||||
* mark/restore ability.
|
||||
*/
|
||||
if (list_length(mapath->subpaths) == 1)
|
||||
return ExecSupportsMarkRestore((Path *) linitial(mapath->subpaths));
|
||||
/* Otherwise, MergeAppend can't handle it */
|
||||
return false;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
Reference in New Issue
Block a user