diff --git a/src/backend/optimizer/path/joinpath.c b/src/backend/optimizer/path/joinpath.c
index 95538c5..8105ffe 100644
--- a/src/backend/optimizer/path/joinpath.c
+++ b/src/backend/optimizer/path/joinpath.c
@@ -58,7 +58,9 @@ static void generate_mergejoin_paths(PlannerInfo *root,
 						 JoinPathExtraData *extra,
 						 bool useallclauses,
 						 Path *inner_cheapest_total,
-						 List *merge_pathkeys);
+						 List *merge_pathkeys,
+						 bool is_partial);
+
 
 
 /*
@@ -481,6 +483,76 @@ try_mergejoin_path(PlannerInfo *root,
 }
 
 /*
+ * try_partial_mergejoin_path
+ *	  Consider a merge join path; if it appears useful, push it into
+ *	  the joinrel's pathlist via add_path().
+ */
+static void
+try_partial_mergejoin_path(PlannerInfo *root,
+				   RelOptInfo *joinrel,
+				   Path *outer_path,
+				   Path *inner_path,
+				   List *pathkeys,
+				   List *mergeclauses,
+				   List *outersortkeys,
+				   List *innersortkeys,
+				   JoinType jointype,
+				   JoinPathExtraData *extra)
+{
+	JoinCostWorkspace workspace;
+
+	/*
+	 * See comments in try_partial_nestloop_path().
+	 */
+	Assert(bms_is_empty(joinrel->lateral_relids));
+	if (inner_path->param_info != NULL)
+	{
+		Relids		inner_paramrels = inner_path->param_info->ppi_req_outer;
+
+		if (!bms_is_subset(inner_paramrels, outer_path->parent->relids))
+			return;
+	}
+
+	/*
+	 * If the given paths are already well enough ordered, we can skip doing
+	 * an explicit sort.
+	 */
+	if (outersortkeys &&
+		pathkeys_contained_in(outersortkeys, outer_path->pathkeys))
+		outersortkeys = NIL;
+	if (innersortkeys &&
+		pathkeys_contained_in(innersortkeys, inner_path->pathkeys))
+		innersortkeys = NIL;
+
+	/*
+	 * See comments in try_nestloop_path().
+	 */
+	initial_cost_mergejoin(root, &workspace, jointype, mergeclauses,
+						   outer_path, inner_path,
+						   outersortkeys, innersortkeys,
+						   extra->sjinfo);
+
+	if (!add_partial_path_precheck(joinrel, workspace.total_cost, pathkeys))
+		return;
+
+	/* Might be good enough to be worth trying, so let's try it. */
+	add_partial_path(joinrel, (Path *)
+			 create_mergejoin_path(root,
+								   joinrel,
+								   jointype,
+								   &workspace,
+								   extra->sjinfo,
+								   outer_path,
+								   inner_path,
+								   extra->restrictlist,
+								   pathkeys,
+								   NULL,
+								   mergeclauses,
+								   outersortkeys,
+								   innersortkeys));
+}
+
+/*
  * try_hashjoin_path
  *	  Consider a hash join path; if it appears useful, push it into
  *	  the joinrel's pathlist via add_path().
@@ -649,6 +721,7 @@ sort_inner_and_outer(PlannerInfo *root,
 					 JoinType jointype,
 					 JoinPathExtraData *extra)
 {
+	JoinType	save_jointype = jointype;
 	Path	   *outer_path;
 	Path	   *inner_path;
 	List	   *all_pathkeys;
@@ -782,6 +855,37 @@ sort_inner_and_outer(PlannerInfo *root,
 						   innerkeys,
 						   jointype,
 						   extra);
+
+		/*
+		 * If the joinrel is parallel-safe, we may be able to consider a
+		 * partial merge join.  However, we can't handle JOIN_UNIQUE_OUTER,
+		 * because the outer path will be partial, and therefore we won't be
+		 * able to properly guarantee uniqueness.  Similarly, we can't handle
+		 * JOIN_FULL and JOIN_RIGHT, because they can produce false null
+		 * extended rows.  Also, the resulting path must not be parameterized.
+		 */
+		if (joinrel->consider_parallel &&
+			save_jointype != JOIN_UNIQUE_OUTER &&
+			jointype != JOIN_FULL &&
+			jointype != JOIN_RIGHT &&
+			outerrel->partial_pathlist != NIL &&
+			bms_is_empty(joinrel->lateral_relids) &&
+			inner_path->parallel_safe)
+		{
+			Path *cheapest_partial_outer =
+							(Path *) linitial(outerrel->partial_pathlist);
+
+			try_partial_mergejoin_path(root,
+									   joinrel,
+									   cheapest_partial_outer,
+									   inner_path,
+									   merge_pathkeys,
+									   cur_mergeclauses,
+									   outerkeys,
+									   innerkeys,
+									   jointype,
+									   extra);
+		}
 	}
 }
 
@@ -798,6 +902,8 @@ sort_inner_and_outer(PlannerInfo *root,
  * some sort key requirements).  So, we consider truncations of the
  * mergeclause list as well as the full list.  (Ideally we'd consider all
  * subsets of the mergeclause list, but that seems way too expensive.)
+ *
+ * is_partial passed true for generating partial merge join paths.
  */
 static void
 generate_mergejoin_paths(PlannerInfo *root,
@@ -808,7 +914,8 @@ generate_mergejoin_paths(PlannerInfo *root,
 						 JoinPathExtraData *extra,
 						 bool useallclauses,
 						 Path *inner_cheapest_total,
-						 List *merge_pathkeys)
+						 List *merge_pathkeys,
+						 bool is_partial)
 {
 	List	   *mergeclauses;
 	List	   *innersortkeys;
@@ -859,16 +966,30 @@ generate_mergejoin_paths(PlannerInfo *root,
 	 * try_mergejoin_path will do the right thing if inner_cheapest_total
 	 * is already correctly sorted.)
 	 */
-	try_mergejoin_path(root,
-					   joinrel,
-					   outerpath,
-					   inner_cheapest_total,
-					   merge_pathkeys,
-					   mergeclauses,
-					   NIL,
-					   innersortkeys,
-					   jointype,
-					   extra);
+	if (!is_partial)
+		try_mergejoin_path(root,
+						joinrel,
+						outerpath,
+						inner_cheapest_total,
+						merge_pathkeys,
+						mergeclauses,
+						NIL,
+						innersortkeys,
+						jointype,
+						extra);
+
+	/* Generate partial path if inner is parallel safe. */
+	else if (inner_cheapest_total->parallel_safe)
+		try_partial_mergejoin_path(root,
+						joinrel,
+						outerpath,
+						inner_cheapest_total,
+						merge_pathkeys,
+						mergeclauses,
+						NIL,
+						innersortkeys,
+						jointype,
+						extra);
 
 	/* Can't do anything else if inner path needs to be unique'd */
 	if (save_jointype == JOIN_UNIQUE_INNER)
@@ -955,16 +1076,30 @@ generate_mergejoin_paths(PlannerInfo *root,
 			}
 			else
 				newclauses = mergeclauses;
-			try_mergejoin_path(root,
-							   joinrel,
-							   outerpath,
-							   innerpath,
-							   merge_pathkeys,
-							   newclauses,
-							   NIL,
-							   NIL,
-							   jointype,
-							   extra);
+			if (!is_partial)
+				try_mergejoin_path(root,
+								joinrel,
+								outerpath,
+								innerpath,
+								merge_pathkeys,
+								newclauses,
+								NIL,
+								NIL,
+								jointype,
+								extra);
+			/* Generate partial path only if innerpath is parallel safe. */
+			else if (innerpath->parallel_safe)
+				try_partial_mergejoin_path(root,
+										   joinrel,
+										   outerpath,
+										   innerpath,
+										   merge_pathkeys,
+										   newclauses,
+										   NIL,
+										   NIL,
+										   jointype,
+										   extra);
+
 			cheapest_total_inner = innerpath;
 		}
 		/* Same on the basis of cheapest startup cost ... */
@@ -998,16 +1133,29 @@ generate_mergejoin_paths(PlannerInfo *root,
 					else
 						newclauses = mergeclauses;
 				}
-				try_mergejoin_path(root,
-								   joinrel,
-								   outerpath,
-								   innerpath,
-								   merge_pathkeys,
-								   newclauses,
-								   NIL,
-								   NIL,
-								   jointype,
-								   extra);
+				if (!is_partial)
+					try_mergejoin_path(root,
+									   joinrel,
+									   outerpath,
+									   innerpath,
+									   merge_pathkeys,
+									   newclauses,
+									   NIL,
+									   NIL,
+									   jointype,
+									   extra);
+				/* Generate partial path only if innerpath is parallel safe. */
+				else if (innerpath->parallel_safe)
+					try_partial_mergejoin_path(root,
+											   joinrel,
+											   outerpath,
+											   innerpath,
+											   merge_pathkeys,
+											   newclauses,
+											   NIL,
+											   NIL,
+											   jointype,
+											   extra);
 			}
 			cheapest_startup_inner = innerpath;
 		}
@@ -1218,22 +1366,59 @@ match_unsorted_outer(PlannerInfo *root,
 		/* Generate merge join paths for the outer path */
 		generate_mergejoin_paths(root, joinrel, innerrel, outerpath,
 								 save_jointype, extra, useallclauses,
-								 inner_cheapest_total, merge_pathkeys);
+								 inner_cheapest_total, merge_pathkeys,
+								 false);
 	}
 
 	/*
-	 * If the joinrel is parallel-safe and the join type supports nested
-	 * loops, we may be able to consider a partial nestloop plan.  However, we
-	 * can't handle JOIN_UNIQUE_OUTER, because the outer path will be partial,
-	 * and therefore we won't be able to properly guarantee uniqueness.  Nor
-	 * can we handle extra_lateral_rels, since partial paths must not be
-	 * parameterized.
+	 * Consider partial nestloop and mergejoin plan if the joinrel is
+	 * parallel-safe. However, we can't handle JOIN_UNIQUE_OUTER, because
+	 * the outer path will be partial, and therefore we won't be able to
+	 * properly guarantee uniqueness.  Nor can we handle extra_lateral_rels,
+	 * since partial paths must not be parameterized.
+	 * Similarly, we can't handle JOIN_FULL and JOIN_RIGHT, because they
+	 * can produce false null extended rows.
 	 */
-	if (joinrel->consider_parallel && nestjoinOK &&
-		save_jointype != JOIN_UNIQUE_OUTER &&
-		bms_is_empty(joinrel->lateral_relids))
+	if (!joinrel->consider_parallel ||
+		save_jointype == JOIN_UNIQUE_OUTER ||
+		!bms_is_empty(joinrel->lateral_relids) ||
+		jointype == JOIN_FULL ||
+		jointype == JOIN_RIGHT)
+		return;
+
+	if (nestjoinOK)
 		consider_parallel_nestloop(root, joinrel, outerrel, innerrel,
 								   save_jointype, extra);
+
+	/* Can't generate mergejoin path if inner rel is parameterized by outer */
+	if (inner_cheapest_total != NULL)
+	{
+		ListCell   *lc1;
+		JoinType	save_jointype = jointype;
+
+		if (jointype == JOIN_UNIQUE_INNER)
+			jointype = JOIN_INNER;
+
+		/* generate merge join path for each partial outer path */
+		foreach(lc1, outerrel->partial_pathlist)
+		{
+			Path	   *outerpath = (Path *) lfirst(lc1);
+			List	   *merge_pathkeys;
+
+			/*
+			 * Figure out what useful ordering any paths we create
+			 * will have.
+			 */
+			merge_pathkeys = build_join_pathkeys(root, joinrel, jointype,
+											   outerpath->pathkeys);
+
+			generate_mergejoin_paths(root, joinrel, innerrel, outerpath,
+									 save_jointype, extra, false,
+									 inner_cheapest_total, merge_pathkeys,
+									 true);
+		}
+
+	}
 }
 
 /*
