@@ -298,12 +298,18 @@ recurse_set_operations(Node *setOp, PlannerInfo *root,
298298 */
299299set_subquery_size_estimates (root ,rel );
300300
301+ /*
302+ * Since we may want to add a partial path to this relation, we must
303+ * set its consider_parallel flag correctly.
304+ */
305+ final_rel = fetch_upper_rel (subroot ,UPPERREL_FINAL ,NULL );
306+ rel -> consider_parallel = final_rel -> consider_parallel ;
307+
301308/*
302309 * For the moment, we consider only a single Path for the subquery.
303310 * This should change soon (make it look more like
304311 * set_subquery_pathlist).
305312 */
306- final_rel = fetch_upper_rel (subroot ,UPPERREL_FINAL ,NULL );
307313subpath = get_cheapest_fractional_path (final_rel ,
308314root -> tuple_fraction );
309315
@@ -320,6 +326,23 @@ recurse_set_operations(Node *setOp, PlannerInfo *root,
320326
321327add_path (rel ,path );
322328
329+ /*
330+ * If we have a partial path for the child relation, we can use that
331+ * to build a partial path for this relation. But there's no point in
332+ * considering any path but the cheapest.
333+ */
334+ if (final_rel -> partial_pathlist != NIL )
335+ {
336+ Path * partial_subpath ;
337+ Path * partial_path ;
338+
339+ partial_subpath = linitial (final_rel -> partial_pathlist );
340+ partial_path = (Path * )
341+ create_subqueryscan_path (root ,rel ,partial_subpath ,
342+ NIL ,NULL );
343+ add_partial_path (rel ,partial_path );
344+ }
345+
323346/*
324347 * Estimate number of groups if caller wants it. If the subquery used
325348 * grouping or aggregation, its output is probably mostly unique
@@ -552,6 +575,9 @@ generate_union_paths(SetOperationStmt *op, PlannerInfo *root,
552575double save_fraction = root -> tuple_fraction ;
553576ListCell * lc ;
554577List * pathlist = NIL ;
578+ List * partial_pathlist = NIL ;
579+ bool partial_paths_valid = true;
580+ bool consider_parallel = true;
555581List * rellist ;
556582List * tlist_list ;
557583List * tlist ;
@@ -591,18 +617,34 @@ generate_union_paths(SetOperationStmt *op, PlannerInfo *root,
591617
592618* pTargetList = tlist ;
593619
594- /* Build pathlist and relid set. */
620+ /* Build pathlists and relid set. */
595621foreach (lc ,rellist )
596622{
597623RelOptInfo * rel = lfirst (lc );
598624
599625pathlist = lappend (pathlist ,rel -> cheapest_total_path );
626+
627+ if (consider_parallel )
628+ {
629+ if (!rel -> consider_parallel )
630+ {
631+ consider_parallel = false;
632+ partial_paths_valid = false;
633+ }
634+ else if (rel -> partial_pathlist == NIL )
635+ partial_paths_valid = false;
636+ else
637+ partial_pathlist = lappend (partial_pathlist ,
638+ linitial (rel -> partial_pathlist ));
639+ }
640+
600641relids = bms_union (relids ,rel -> relids );
601642}
602643
603644/* Build result relation. */
604645result_rel = fetch_upper_rel (root ,UPPERREL_SETOP ,relids );
605646result_rel -> reltarget = create_pathtarget (root ,tlist );
647+ result_rel -> consider_parallel = consider_parallel ;
606648
607649/*
608650 * Append the child results together.
@@ -626,6 +668,53 @@ generate_union_paths(SetOperationStmt *op, PlannerInfo *root,
626668 */
627669result_rel -> rows = path -> rows ;
628670
671+ /*
672+ * Now consider doing the same thing using the partial paths plus Append
673+ * plus Gather.
674+ */
675+ if (partial_paths_valid )
676+ {
677+ Path * ppath ;
678+ ListCell * lc ;
679+ int parallel_workers = 0 ;
680+
681+ /* Find the highest number of workers requested for any subpath. */
682+ foreach (lc ,partial_pathlist )
683+ {
684+ Path * path = lfirst (lc );
685+
686+ parallel_workers = Max (parallel_workers ,path -> parallel_workers );
687+ }
688+ Assert (parallel_workers > 0 );
689+
690+ /*
691+ * If the use of parallel append is permitted, always request at least
692+ * log2(# of children) paths. We assume it can be useful to have
693+ * extra workers in this case because they will be spread out across
694+ * the children. The precise formula is just a guess; see
695+ * add_paths_to_append_rel.
696+ */
697+ if (enable_parallel_append )
698+ {
699+ parallel_workers = Max (parallel_workers ,
700+ fls (list_length (partial_pathlist )));
701+ parallel_workers = Min (parallel_workers ,
702+ max_parallel_workers_per_gather );
703+ }
704+ Assert (parallel_workers > 0 );
705+
706+ ppath = (Path * )
707+ create_append_path (result_rel ,NIL ,partial_pathlist ,
708+ NULL ,parallel_workers ,enable_parallel_append ,
709+ NIL ,-1 );
710+ ppath = (Path * )
711+ create_gather_path (root ,result_rel ,ppath ,
712+ result_rel -> reltarget ,NULL ,NULL );
713+ if (!op -> all )
714+ ppath = make_union_unique (op ,ppath ,tlist ,root );
715+ add_path (result_rel ,ppath );
716+ }
717+
629718/* Undo effects of possibly forcing tuple_fraction to 0 */
630719root -> tuple_fraction = save_fraction ;
631720