@@ -1500,6 +1500,7 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
15001500 PathTarget * grouping_target ;
15011501 PathTarget * scanjoin_target ;
15021502 bool have_grouping ;
1503+ bool scanjoin_target_parallel_safe = false;
15031504 WindowFuncLists * wflists = NULL ;
15041505 List * activeWindows = NIL ;
15051506 List * rollup_lists = NIL ;
@@ -1730,7 +1731,16 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
17301731 scanjoin_target = grouping_target ;
17311732
17321733 /*
1733- * Forcibly apply that target to all the Paths for the scan/join rel.
1734+ * Check whether scan/join target is parallel safe ... unless there
1735+ * are no partial paths, in which case we don't care.
1736+ */
1737+ if (current_rel -> partial_pathlist &&
1738+ !has_parallel_hazard ((Node * ) scanjoin_target -> exprs , false))
1739+ scanjoin_target_parallel_safe = true;
1740+
1741+ /*
1742+ * Forcibly apply scan/join target to all the Paths for the scan/join
1743+ * rel.
17341744 *
17351745 * In principle we should re-run set_cheapest() here to identify the
17361746 * cheapest path, but it seems unlikely that adding the same tlist
@@ -1746,7 +1756,8 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
17461756
17471757 Assert (subpath -> param_info == NULL );
17481758 path = apply_projection_to_path (root , current_rel ,
1749- subpath , scanjoin_target );
1759+ subpath , scanjoin_target ,
1760+ scanjoin_target_parallel_safe );
17501761 /* If we had to add a Result, path is different from subpath */
17511762 if (path != subpath )
17521763 {
@@ -1758,6 +1769,70 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
17581769 }
17591770 }
17601771
1772+ /*
1773+ * Upper planning steps which make use of the top scan/join rel's
1774+ * partial pathlist will expect partial paths for that rel to produce
1775+ * the same output as complete paths ... and we just changed the
1776+ * output for the complete paths, so we'll need to do the same thing
1777+ * for partial paths.
1778+ */
1779+ if (scanjoin_target_parallel_safe )
1780+ {
1781+ /*
1782+ * Apply the scan/join target to each partial path. Otherwise,
1783+ * anything that attempts to use the partial paths for further
1784+ * upper planning may go wrong.
1785+ */
1786+ foreach (lc , current_rel -> partial_pathlist )
1787+ {
1788+ Path * subpath = (Path * ) lfirst (lc );
1789+ Path * newpath ;
1790+
1791+ /*
1792+ * We can't use apply_projection_to_path() here, because there
1793+ * could already be pointers to these paths, and therefore we
1794+ * cannot modify them in place. Instead, we must use
1795+ * create_projection_path(). The good news is this won't
1796+ * actually insert a Result node into the final plan unless
1797+ * it's needed, but the bad news is that it will charge for
1798+ * the node whether it's needed or not. Therefore, if the
1799+ * target list is already what we need it to be, just leave
1800+ * this partial path alone.
1801+ */
1802+ if (equal (scanjoin_target -> exprs , subpath -> pathtarget -> exprs ))
1803+ continue ;
1804+
1805+ Assert (subpath -> param_info == NULL );
1806+ newpath = (Path * ) create_projection_path (root ,
1807+ current_rel ,
1808+ subpath ,
1809+ scanjoin_target );
1810+ if (is_projection_capable_path (subpath ))
1811+ {
1812+ /*
1813+ * Since the target lists differ, a projection path is
1814+ * essential, but it will disappear at plan creation time
1815+ * because the subpath is projection-capable. So avoid
1816+ * charging anything for the disappearing node.
1817+ */
1818+ newpath -> startup_cost = subpath -> startup_cost ;
1819+ newpath -> total_cost = subpath -> total_cost ;
1820+ }
1821+
1822+ lfirst (lc ) = newpath ;
1823+ }
1824+ }
1825+ else
1826+ {
1827+ /*
1828+ * In the unfortunate event that scanjoin_target is not
1829+ * parallel-safe, we can't apply it to the partial paths; in that
1830+ * case, we'll need to forget about the partial paths, which
1831+ * aren't valid input for upper planning steps.
1832+ */
1833+ current_rel -> partial_pathlist = NIL ;
1834+ }
1835+
17611836 /*
17621837 * Save the various upper-rel PathTargets we just computed into
17631838 * root->upper_targets[]. The core code doesn't use this, but it
@@ -4153,7 +4228,7 @@ create_ordered_paths(PlannerInfo *root,
41534228 /* Add projection step if needed */
41544229 if (path -> pathtarget != target )
41554230 path = apply_projection_to_path (root , ordered_rel ,
4156- path , target );
4231+ path , target , false );
41574232
41584233 add_path (ordered_rel , path );
41594234 }
0 commit comments