@@ -1500,6 +1500,7 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
1500
1500
PathTarget * grouping_target ;
1501
1501
PathTarget * scanjoin_target ;
1502
1502
bool have_grouping ;
1503
+ bool scanjoin_target_parallel_safe = false;
1503
1504
WindowFuncLists * wflists = NULL ;
1504
1505
List * activeWindows = NIL ;
1505
1506
List * rollup_lists = NIL ;
@@ -1730,7 +1731,16 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
1730
1731
scanjoin_target = grouping_target ;
1731
1732
1732
1733
/*
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.
1734
1744
*
1735
1745
* In principle we should re-run set_cheapest() here to identify the
1736
1746
* cheapest path, but it seems unlikely that adding the same tlist
@@ -1746,7 +1756,8 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
1746
1756
1747
1757
Assert (subpath -> param_info == NULL );
1748
1758
path = apply_projection_to_path (root , current_rel ,
1749
- subpath , scanjoin_target );
1759
+ subpath , scanjoin_target ,
1760
+ scanjoin_target_parallel_safe );
1750
1761
/* If we had to add a Result, path is different from subpath */
1751
1762
if (path != subpath )
1752
1763
{
@@ -1758,6 +1769,70 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
1758
1769
}
1759
1770
}
1760
1771
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
+
1761
1836
/*
1762
1837
* Save the various upper-rel PathTargets we just computed into
1763
1838
* root->upper_targets[]. The core code doesn't use this, but it
@@ -4153,7 +4228,7 @@ create_ordered_paths(PlannerInfo *root,
4153
4228
/* Add projection step if needed */
4154
4229
if (path -> pathtarget != target )
4155
4230
path = apply_projection_to_path (root , ordered_rel ,
4156
- path , target );
4231
+ path , target , false );
4157
4232
4158
4233
add_path (ordered_rel , path );
4159
4234
}
0 commit comments