diff --git a/src/backend/optimizer/geqo/geqo_eval.c b/src/backend/optimizer/geqo/geqo_eval.c
new file mode 100644
index b5cab0c..d0e07bd
*** a/src/backend/optimizer/geqo/geqo_eval.c
--- b/src/backend/optimizer/geqo/geqo_eval.c
*************** typedef struct
*** 40,46 ****
  } Clump;
  
  static List *merge_clump(PlannerInfo *root, List *clumps, Clump *new_clump,
! 			bool force);
  static bool desirable_join(PlannerInfo *root,
  			   RelOptInfo *outer_rel, RelOptInfo *inner_rel);
  
--- 40,46 ----
  } Clump;
  
  static List *merge_clump(PlannerInfo *root, List *clumps, Clump *new_clump,
! 			int num_gene, bool force);
  static bool desirable_join(PlannerInfo *root,
  			   RelOptInfo *outer_rel, RelOptInfo *inner_rel);
  
*************** gimme_tree(PlannerInfo *root, Gene *tour
*** 196,202 ****
  		cur_clump->size = 1;
  
  		/* Merge it into the clumps list, using only desirable joins */
! 		clumps = merge_clump(root, clumps, cur_clump, false);
  	}
  
  	if (list_length(clumps) > 1)
--- 196,202 ----
  		cur_clump->size = 1;
  
  		/* Merge it into the clumps list, using only desirable joins */
! 		clumps = merge_clump(root, clumps, cur_clump, num_gene, false);
  	}
  
  	if (list_length(clumps) > 1)
*************** gimme_tree(PlannerInfo *root, Gene *tour
*** 210,216 ****
  		{
  			Clump	   *clump = (Clump *) lfirst(lc);
  
! 			fclumps = merge_clump(root, fclumps, clump, true);
  		}
  		clumps = fclumps;
  	}
--- 210,216 ----
  		{
  			Clump	   *clump = (Clump *) lfirst(lc);
  
! 			fclumps = merge_clump(root, fclumps, clump, num_gene, true);
  		}
  		clumps = fclumps;
  	}
*************** gimme_tree(PlannerInfo *root, Gene *tour
*** 235,241 ****
   * "desirable" joins.
   */
  static List *
! merge_clump(PlannerInfo *root, List *clumps, Clump *new_clump, bool force)
  {
  	ListCell   *prev;
  	ListCell   *lc;
--- 235,242 ----
   * "desirable" joins.
   */
  static List *
! merge_clump(PlannerInfo *root, List *clumps, Clump *new_clump, int num_gene,
! 			bool force)
  {
  	ListCell   *prev;
  	ListCell   *lc;
*************** merge_clump(PlannerInfo *root, List *clu
*** 264,271 ****
  			/* Keep searching if join order is not valid */
  			if (joinrel)
  			{
! 				/* Create GatherPaths for any useful partial paths for rel */
! 				generate_gather_paths(root, joinrel);
  
  				/* Find and save the cheapest paths for this joinrel */
  				set_cheapest(joinrel);
--- 265,278 ----
  			/* Keep searching if join order is not valid */
  			if (joinrel)
  			{
! 				/*
! 				 * Create GatherPaths for any useful partial paths for rel
! 				 * other than top-level rel.  The gather path for top-level
! 				 * rel is generated once path target is available.  See
! 				 * grouping_planner.
! 				 */
! 				if (old_clump->size + new_clump->size < num_gene)
! 					generate_gather_paths(root, joinrel, NULL);
  
  				/* Find and save the cheapest paths for this joinrel */
  				set_cheapest(joinrel);
*************** merge_clump(PlannerInfo *root, List *clu
*** 283,289 ****
  				 * others.  When no further merge is possible, we'll reinsert
  				 * it into the list.
  				 */
! 				return merge_clump(root, clumps, old_clump, force);
  			}
  		}
  		prev = lc;
--- 290,296 ----
  				 * others.  When no further merge is possible, we'll reinsert
  				 * it into the list.
  				 */
! 				return merge_clump(root, clumps, old_clump, num_gene, force);
  			}
  		}
  		prev = lc;
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
new file mode 100644
index 5b746a9..74512da
*** a/src/backend/optimizer/path/allpaths.c
--- b/src/backend/optimizer/path/allpaths.c
*************** set_rel_pathlist(PlannerInfo *root, RelO
*** 480,493 ****
  	}
  
  	/*
! 	 * If this is a baserel, consider gathering any partial paths we may have
! 	 * created for it.  (If we tried to gather inheritance children, we could
! 	 * end up with a very large number of gather nodes, each trying to grab
! 	 * its own pool of workers, so don't do this for otherrels.  Instead,
! 	 * we'll consider gathering partial paths for the parent appendrel.)
  	 */
! 	if (rel->reloptkind == RELOPT_BASEREL)
! 		generate_gather_paths(root, rel);
  
  	/*
  	 * Allow a plugin to editorialize on the set of Paths for this base
--- 480,497 ----
  	}
  
  	/*
! 	 * If this is a baserel and not the top-level rel, consider gathering any
! 	 * partial paths we may have created for it.  (If we tried to gather
! 	 * inheritance children, we could end up with a very large number of
! 	 * gather nodes, each trying to grab its own pool of workers, so don't do
! 	 * this for otherrels.  Instead, we'll consider gathering partial paths
! 	 * for the parent appendrel.).  The gather path for top-level rel is
! 	 * generated once path target is available.  See grouping_planner.
  	 */
! 	if (rel->reloptkind == RELOPT_BASEREL &&
! 		root->simple_rel_array_size > 2 &&
! 		!root->append_rel_list)
! 		generate_gather_paths(root, rel, NULL);
  
  	/*
  	 * Allow a plugin to editorialize on the set of Paths for this base
*************** set_worktable_pathlist(PlannerInfo *root
*** 2228,2238 ****
   *		Gather Merge on top of a partial path.
   *
   * This must not be called until after we're done creating all partial paths
!  * for the specified relation.  (Otherwise, add_partial_path might delete a
!  * path that some GatherPath or GatherMergePath has a reference to.)
   */
  void
! generate_gather_paths(PlannerInfo *root, RelOptInfo *rel)
  {
  	Path	   *cheapest_partial_path;
  	Path	   *simple_gather_path;
--- 2232,2243 ----
   *		Gather Merge on top of a partial path.
   *
   * This must not be called until after we're done creating all partial paths
!  * for the specified relation (Otherwise, add_partial_path might delete a
!  * path that some GatherPath or GatherMergePath has a reference to.) and path
!  * target for top level scan/join node is available.
   */
  void
! generate_gather_paths(PlannerInfo *root, RelOptInfo *rel, PathTarget *target)
  {
  	Path	   *cheapest_partial_path;
  	Path	   *simple_gather_path;
*************** generate_gather_paths(PlannerInfo *root,
*** 2251,2256 ****
--- 2256,2266 ----
  	simple_gather_path = (Path *)
  		create_gather_path(root, rel, cheapest_partial_path, rel->reltarget,
  						   NULL, NULL);
+ 
+ 	/* Add projection step if needed */
+ 	if (target && simple_gather_path->pathtarget != target)
+ 		simple_gather_path = apply_projection_to_path(root, rel, simple_gather_path, target);
+ 
  	add_path(rel, simple_gather_path);
  
  	/*
*************** generate_gather_paths(PlannerInfo *root,
*** 2260,2273 ****
  	foreach(lc, rel->partial_pathlist)
  	{
  		Path	   *subpath = (Path *) lfirst(lc);
! 		GatherMergePath *path;
  
  		if (subpath->pathkeys == NIL)
  			continue;
  
! 		path = create_gather_merge_path(root, rel, subpath, rel->reltarget,
! 										subpath->pathkeys, NULL, NULL);
! 		add_path(rel, &path->path);
  	}
  }
  
--- 2270,2287 ----
  	foreach(lc, rel->partial_pathlist)
  	{
  		Path	   *subpath = (Path *) lfirst(lc);
! 		Path	   *path;
  
  		if (subpath->pathkeys == NIL)
  			continue;
  
! 		path = (Path *) create_gather_merge_path(root, rel, subpath, rel->reltarget,
! 												 subpath->pathkeys, NULL, NULL);
! 		/* Add projection step if needed */
! 		if (target && path->pathtarget != target)
! 			path = apply_projection_to_path(root, rel, path, target);
! 
! 		add_path(rel, path);
  	}
  }
  
*************** standard_join_search(PlannerInfo *root, 
*** 2432,2439 ****
  		{
  			rel = (RelOptInfo *) lfirst(lc);
  
! 			/* Create GatherPaths for any useful partial paths for rel */
! 			generate_gather_paths(root, rel);
  
  			/* Find and save the cheapest paths for this rel */
  			set_cheapest(rel);
--- 2446,2458 ----
  		{
  			rel = (RelOptInfo *) lfirst(lc);
  
! 			/*
! 			 * Create GatherPaths for any useful partial paths for rel other
! 			 * than top-level rel.  The gather path for top-level rel is
! 			 * generated once path target is available.  See grouping_planner.
! 			 */
! 			if (lev < levels_needed)
! 				generate_gather_paths(root, rel, NULL);
  
  			/* Find and save the cheapest paths for this rel */
  			set_cheapest(rel);
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
new file mode 100644
index 7f146d6..659f27d
*** a/src/backend/optimizer/plan/planner.c
--- b/src/backend/optimizer/plan/planner.c
*************** grouping_planner(PlannerInfo *root, bool
*** 1860,1865 ****
--- 1860,1877 ----
  		}
  
  		/*
+ 		 * Consider ways to implement parallel paths.  We always skip
+ 		 * generating parallel path for top level scan/join nodes till the
+ 		 * pathtarget is computed.  This is to ensure that we can account for
+ 		 * the fact that most of the target evaluation work will be performed
+ 		 * in workers.
+ 		 */
+ 		generate_gather_paths(root, current_rel, scanjoin_target);
+ 
+ 		/* Set or update cheapest_total_path and related fields */
+ 		set_cheapest(current_rel);
+ 
+ 		/*
  		 * 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
diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c
new file mode 100644
index 26567cb..41f98b3
*** a/src/backend/optimizer/util/pathnode.c
--- b/src/backend/optimizer/util/pathnode.c
*************** apply_projection_to_path(PlannerInfo *ro
*** 2408,2423 ****
  		 * projection-capable, so as to avoid modifying the subpath in place.
  		 * It seems unlikely at present that there could be any other
  		 * references to the subpath, but better safe than sorry.
- 		 *
- 		 * Note that we don't change the GatherPath's cost estimates; it might
- 		 * be appropriate to do so, to reflect the fact that the bulk of the
- 		 * target evaluation will happen in workers.
  		 */
  		gpath->subpath = (Path *)
  			create_projection_path(root,
  								   gpath->subpath->parent,
  								   gpath->subpath,
  								   target);
  	}
  	else if (path->parallel_safe &&
  			 !is_parallel_safe(root, (Node *) target->exprs))
--- 2408,2434 ----
  		 * projection-capable, so as to avoid modifying the subpath in place.
  		 * It seems unlikely at present that there could be any other
  		 * references to the subpath, but better safe than sorry.
  		 */
  		gpath->subpath = (Path *)
  			create_projection_path(root,
  								   gpath->subpath->parent,
  								   gpath->subpath,
  								   target);
+ 
+ 		/*
+ 		 * Adjust the cost of GatherPath to reflect the fact that the bulk of
+ 		 * the target evaluation will happen in workers.
+ 		 */
+ 		if (((ProjectionPath *) gpath->subpath)->dummypp)
+ 		{
+ 			path->total_cost -= (target->cost.per_tuple - oldcost.per_tuple) * path->rows;
+ 			path->total_cost += (target->cost.per_tuple - oldcost.per_tuple) * gpath->subpath->rows;
+ 		}
+ 		else
+ 		{
+ 			path->total_cost -= (target->cost.per_tuple - oldcost.per_tuple) * path->rows;
+ 			path->total_cost += (cpu_tuple_cost + target->cost.per_tuple) * gpath->subpath->rows;
+ 		}
  	}
  	else if (path->parallel_safe &&
  			 !is_parallel_safe(root, (Node *) target->exprs))
diff --git a/src/include/optimizer/paths.h b/src/include/optimizer/paths.h
new file mode 100644
index 4e06b2e..61694a0
*** a/src/include/optimizer/paths.h
--- b/src/include/optimizer/paths.h
*************** extern void set_dummy_rel_pathlist(RelOp
*** 53,59 ****
  extern RelOptInfo *standard_join_search(PlannerInfo *root, int levels_needed,
  					 List *initial_rels);
  
! extern void generate_gather_paths(PlannerInfo *root, RelOptInfo *rel);
  extern int compute_parallel_worker(RelOptInfo *rel, double heap_pages,
  						double index_pages);
  extern void create_partial_bitmap_paths(PlannerInfo *root, RelOptInfo *rel,
--- 53,60 ----
  extern RelOptInfo *standard_join_search(PlannerInfo *root, int levels_needed,
  					 List *initial_rels);
  
! extern void generate_gather_paths(PlannerInfo *root, RelOptInfo *rel,
! 					  PathTarget *target);
  extern int compute_parallel_worker(RelOptInfo *rel, double heap_pages,
  						double index_pages);
  extern void create_partial_bitmap_paths(PlannerInfo *root, RelOptInfo *rel,
diff --git a/src/test/regress/expected/select_parallel.out b/src/test/regress/expected/select_parallel.out
new file mode 100644
index 2ae600f..232a455
*** a/src/test/regress/expected/select_parallel.out
--- b/src/test/regress/expected/select_parallel.out
*************** explain (costs off)
*** 101,106 ****
--- 101,123 ----
           ->  Parallel Index Only Scan using tenk1_unique1 on tenk1
  (5 rows)
  
+ -- test that parallel plan gets selected when target list contains costly
+ -- function
+ create or replace function costly_func(var1 integer) returns integer
+ as $$
+ begin
+         return var1 + 10;
+ end;
+ $$ language plpgsql PARALLEL SAFE Cost 100000;
+ explain (costs off) select ten, costly_func(ten) from tenk1;
+             QUERY PLAN            
+ ----------------------------------
+  Gather
+    Workers Planned: 4
+    ->  Parallel Seq Scan on tenk1
+ (3 rows)
+ 
+ drop function costly_func(var1 integer);
  -- test parallel plans for queries containing un-correlated subplans.
  alter table tenk2 set (parallel_workers = 0);
  explain (costs off)
diff --git a/src/test/regress/sql/select_parallel.sql b/src/test/regress/sql/select_parallel.sql
new file mode 100644
index 89fe80a..2b8072d
*** a/src/test/regress/sql/select_parallel.sql
--- b/src/test/regress/sql/select_parallel.sql
*************** explain (costs off)
*** 39,44 ****
--- 39,55 ----
  	select  sum(parallel_restricted(unique1)) from tenk1
  	group by(parallel_restricted(unique1));
  
+ -- test that parallel plan gets selected when target list contains costly
+ -- function
+ create or replace function costly_func(var1 integer) returns integer
+ as $$
+ begin
+         return var1 + 10;
+ end;
+ $$ language plpgsql PARALLEL SAFE Cost 100000;
+ explain (costs off) select ten, costly_func(ten) from tenk1;
+ drop function costly_func(var1 integer);
+ 
  -- test parallel plans for queries containing un-correlated subplans.
  alter table tenk2 set (parallel_workers = 0);
  explain (costs off)
