PathTarget *grouping_target;
PathTarget *scanjoin_target;
bool have_grouping;
+ bool scanjoin_target_parallel_safe = false;
WindowFuncLists *wflists = NULL;
List *activeWindows = NIL;
List *rollup_lists = NIL;
scanjoin_target = grouping_target;
/*
- * Forcibly apply that target to all the Paths for the scan/join rel.
+ * Check whether scan/join target is parallel safe ... unless there
+ * are no partial paths, in which case we don't care.
+ */
+ if (current_rel->partial_pathlist &&
+ !has_parallel_hazard((Node *) scanjoin_target->exprs, false))
+ scanjoin_target_parallel_safe = true;
+
+ /*
+ * Forcibly apply scan/join target to all the Paths for the scan/join
+ * rel.
*
* In principle we should re-run set_cheapest() here to identify the
* cheapest path, but it seems unlikely that adding the same tlist
Assert(subpath->param_info == NULL);
path = apply_projection_to_path(root, current_rel,
- subpath, scanjoin_target);
+ subpath, scanjoin_target,
+ scanjoin_target_parallel_safe);
/* If we had to add a Result, path is different from subpath */
if (path != subpath)
{
}
}
+ /*
+ * Upper planning steps which make use of the top scan/join rel's
+ * partial pathlist will expect partial paths for that rel to produce
+ * the same output as complete paths ... and we just changed the
+ * output for the complete paths, so we'll need to do the same thing
+ * for partial paths.
+ */
+ if (scanjoin_target_parallel_safe)
+ {
+ /*
+ * Apply the scan/join target to each partial path. Otherwise,
+ * anything that attempts to use the partial paths for further
+ * upper planning may go wrong.
+ */
+ foreach(lc, current_rel->partial_pathlist)
+ {
+ Path *subpath = (Path *) lfirst(lc);
+ Path *newpath;
+
+ /*
+ * We can't use apply_projection_to_path() here, because there
+ * could already be pointers to these paths, and therefore we
+ * cannot modify them in place. Instead, we must use
+ * create_projection_path(). The good news is this won't
+ * actually insert a Result node into the final plan unless
+ * it's needed, but the bad news is that it will charge for
+ * the node whether it's needed or not. Therefore, if the
+ * target list is already what we need it to be, just leave
+ * this partial path alone.
+ */
+ if (equal(scanjoin_target->exprs, subpath->pathtarget->exprs))
+ continue;
+
+ Assert(subpath->param_info == NULL);
+ newpath = (Path *) create_projection_path(root,
+ current_rel,
+ subpath,
+ scanjoin_target);
+ if (is_projection_capable_path(subpath))
+ {
+ /*
+ * Since the target lists differ, a projection path is
+ * essential, but it will disappear at plan creation time
+ * because the subpath is projection-capable. So avoid
+ * charging anything for the disappearing node.
+ */
+ newpath->startup_cost = subpath->startup_cost;
+ newpath->total_cost = subpath->total_cost;
+ }
+
+ lfirst(lc) = newpath;
+ }
+ }
+ else
+ {
+ /*
+ * In the unfortunate event that scanjoin_target is not
+ * parallel-safe, we can't apply it to the partial paths; in that
+ * case, we'll need to forget about the partial paths, which
+ * aren't valid input for upper planning steps.
+ */
+ current_rel->partial_pathlist = NIL;
+ }
+
/*
* Save the various upper-rel PathTargets we just computed into
* root->upper_targets[]. The core code doesn't use this, but it
/* Add projection step if needed */
if (path->pathtarget != target)
path = apply_projection_to_path(root, ordered_rel,
- path, target);
+ path, target, false);
add_path(ordered_rel, path);
}
Filter: (tenk1.stringu1 = 'GRAAAA'::name)
(9 rows)
+-- test parallel plan when group by expression is in target list.
+explain (costs off)
+ select length(stringu1) from tenk1 group by length(stringu1);
+ QUERY PLAN
+---------------------------------------------------
+ Finalize HashAggregate
+ Group Key: (length((stringu1)::text))
+ -> Gather
+ Workers Planned: 4
+ -> Partial HashAggregate
+ Group Key: length((stringu1)::text)
+ -> Parallel Seq Scan on tenk1
+(7 rows)
+
+select length(stringu1) from tenk1 group by length(stringu1);
+ length
+--------
+ 6
+(1 row)
+
+-- test that parallel plan for aggregates is not selected when
+-- target list contains parallel restricted clause.
+explain (costs off)
+ select sum(parallel_restricted(unique1)) from tenk1
+ group by(parallel_restricted(unique1));
+ QUERY PLAN
+----------------------------------------------------
+ HashAggregate
+ Group Key: parallel_restricted(unique1)
+ -> Index Only Scan using tenk1_unique1 on tenk1
+(3 rows)
+
set force_parallel_mode=1;
explain (costs off)
select stringu1::int2 from tenk1 where unique1 = 1;