diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 0463c477e7..910a738c20 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -2270,8 +2270,7 @@ _outRelOptInfo(StringInfo str, const RelOptInfo *node)
 	WRITE_OID_FIELD(userid);
 	WRITE_BOOL_FIELD(useridiscurrent);
 	/* we don't try to print fdwroutine or fdw_private */
-	WRITE_NODE_FIELD(unique_for_rels);
-	/* can't print non_unique_for_rels; BMSes aren't Nodes */
+	/* can't print unique_for_rels/non_unique_for_rels; BMSes aren't Nodes */
 	WRITE_NODE_FIELD(baserestrictinfo);
 	WRITE_UINT_FIELD(baserestrict_min_security);
 	WRITE_NODE_FIELD(joininfo);
@@ -2343,19 +2342,6 @@ _outStatisticExtInfo(StringInfo str, const StatisticExtInfo *node)
 	WRITE_BITMAPSET_FIELD(keys);
 }
 
-static void
-_outUniqueRelInfo(StringInfo str, const UniqueRelInfo *node)
-{
-	WRITE_NODE_TYPE("UNIQUERELINFO");
-
-	WRITE_BITMAPSET_FIELD(outerrelids);
-	if (node->index)
-	{
-		WRITE_OID_FIELD(index->indexoid);
-		WRITE_NODE_FIELD(column_values);
-	}
-}
-
 static void
 _outEquivalenceClass(StringInfo str, const EquivalenceClass *node)
 {
@@ -4109,9 +4095,6 @@ outNode(StringInfo str, const void *obj)
 			case T_StatisticExtInfo:
 				_outStatisticExtInfo(str, obj);
 				break;
-			case T_UniqueRelInfo:
-				_outUniqueRelInfo(str, obj);
-				break;
 			case T_ExtensibleNode:
 				_outExtensibleNode(str, obj);
 				break;
diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c
index 88e61d4c54..3434219dbd 100644
--- a/src/backend/optimizer/path/indxpath.c
+++ b/src/backend/optimizer/path/indxpath.c
@@ -3583,8 +3583,7 @@ ec_member_matches_indexcol(PlannerInfo *root, RelOptInfo *rel,
  * relation_has_unique_index_for
  *	  Determine whether the relation provably has at most one row satisfying
  *	  a set of equality conditions, because the conditions constrain all
- *	  columns of some unique index. If index_info is not null, it is set to
- *	  point to a new UniqueRelInfo containing the index and conditions.
+ *	  columns of some unique index.
  *
  * The conditions can be represented in either or both of two ways:
  * 1. A list of RestrictInfo nodes, where the caller has already determined
@@ -3605,16 +3604,12 @@ ec_member_matches_indexcol(PlannerInfo *root, RelOptInfo *rel,
 bool
 relation_has_unique_index_for(PlannerInfo *root, RelOptInfo *rel,
 							  List *restrictlist,
-							  List *exprlist, List *oprlist,
-							  UniqueRelInfo **unique_info)
+							  List *exprlist, List *oprlist)
 {
 	ListCell   *ic;
 
 	Assert(list_length(exprlist) == list_length(oprlist));
 
-	if (unique_info)
-		*unique_info = NULL;
-
 	/* Short-circuit if no indexes... */
 	if (rel->indexlist == NIL)
 		return false;
@@ -3665,7 +3660,6 @@ relation_has_unique_index_for(PlannerInfo *root, RelOptInfo *rel,
 	{
 		IndexOptInfo *ind = (IndexOptInfo *) lfirst(ic);
 		int			c;
-		List *column_values = NIL;
 
 		/*
 		 * If the index is not unique, or not immediately enforced, or if it's
@@ -3714,9 +3708,6 @@ relation_has_unique_index_for(PlannerInfo *root, RelOptInfo *rel,
 				if (match_index_to_operand(rexpr, c, ind))
 				{
 					matched = true; /* column is unique */
-					column_values = lappend(column_values, rinfo->outer_is_left
-											? get_leftop(rinfo->clause)
-											: get_rightop(rinfo->clause));
 					break;
 				}
 			}
@@ -3759,22 +3750,7 @@ relation_has_unique_index_for(PlannerInfo *root, RelOptInfo *rel,
 
 		/* Matched all key columns of this index? */
 		if (c == ind->nkeycolumns)
-		{
-			if (unique_info)
-			{
-				/* This may be called in GEQO memory context. */
-				MemoryContext oldContext = MemoryContextSwitchTo(root->planner_cxt);
-				*unique_info = makeNode(UniqueRelInfo);
-				(*unique_info)->index = ind;
-				(*unique_info)->column_values = list_copy(column_values);
-				MemoryContextSwitchTo(oldContext);
-			}
-			if (column_values)
-				list_free(column_values);
 			return true;
-		}
-		if (column_values)
-			list_free(column_values);
 	}
 
 	return false;
diff --git a/src/backend/optimizer/path/joinpath.c b/src/backend/optimizer/path/joinpath.c
index 89cd236306..d8ff4bf432 100644
--- a/src/backend/optimizer/path/joinpath.c
+++ b/src/backend/optimizer/path/joinpath.c
@@ -176,8 +176,7 @@ add_paths_to_joinrel(PlannerInfo *root,
 													innerrel,
 													JOIN_INNER,
 													restrictlist,
-													false,
-													NULL /*index_info*/);
+													false);
 			break;
 		default:
 			extra.inner_unique = innerrel_is_unique(root,
@@ -186,8 +185,7 @@ add_paths_to_joinrel(PlannerInfo *root,
 													innerrel,
 													jointype,
 													restrictlist,
-													false,
-													NULL /*index_info*/);
+													false);
 			break;
 	}
 
diff --git a/src/backend/optimizer/plan/analyzejoins.c b/src/backend/optimizer/plan/analyzejoins.c
index a310d89a39..7efcf9f569 100644
--- a/src/backend/optimizer/plan/analyzejoins.c
+++ b/src/backend/optimizer/plan/analyzejoins.c
@@ -34,27 +34,29 @@
 #include "utils/lsyscache.h"
 
 /* local functions */
-static bool join_is_removable(PlannerInfo *root, SpecialJoinInfo *sjinfo);
+static bool leftjoin_is_removable(PlannerInfo *root, SpecialJoinInfo *sjinfo);
 static void remove_rel_from_query(PlannerInfo *root, int relid,
 					  Relids joinrelids);
 static List *remove_rel_from_joinlist(List *joinlist, int relid, int *nremoved);
 static bool rel_supports_distinctness(PlannerInfo *root, RelOptInfo *rel);
 static bool rel_is_distinct_for(PlannerInfo *root, RelOptInfo *rel,
-					List *clause_list, UniqueRelInfo **unique_info);
+					List *clause_list);
 static Oid	distinct_col_search(int colno, List *colnos, List *opids);
 static bool is_innerrel_unique_for(PlannerInfo *root,
 					   Relids joinrelids,
 					   Relids outerrelids,
 					   RelOptInfo *innerrel,
 					   JoinType jointype,
-					   List *restrictlist,
-					   UniqueRelInfo **unique_info);
+					   List *restrictlist);
+static void split_selfjoin_quals(PlannerInfo *root, List *joinquals,
+					 List **selfjoinquals,
+					 List **otherjoinquals);
 
 
 /*
- * remove_useless_joins
- *		Check for relations that don't actually need to be joined at all,
- *		and remove them from the query.
+ * remove_useless_left_joins
+ *		Check for left joined relations that don't actually need to be joined
+ *		at all, and remove them from the query.
  *
  * We are passed the current joinlist and return the updated list.  Other
  * data structures that have to be updated are accessible via "root".
@@ -76,11 +78,11 @@ restart:
 		int			nremoved;
 
 		/* Skip if not removable */
-		if (!join_is_removable(root, sjinfo))
+		if (!leftjoin_is_removable(root, sjinfo))
 			continue;
 
 		/*
-		 * Currently, join_is_removable can only succeed when the sjinfo's
+		 * Currently, leftjoin_is_removable can only succeed when the sjinfo's
 		 * righthand is a single baserel.  Remove that rel from the query and
 		 * joinlist.
 		 */
@@ -148,9 +150,9 @@ clause_sides_match_join(RestrictInfo *rinfo, Relids outerrelids,
 }
 
 /*
- * join_is_removable
- *	  Check whether we need not perform this special join at all, because
- *	  it will just duplicate its left input.
+ * leftjoin_is_removable
+ *	  Check whether we need not perform this left join at all, because it will
+ *	  just duplicate its left input.
  *
  * This is true for a left join for which the join condition cannot match
  * more than one inner-side row.  (There are other possibly interesting
@@ -159,7 +161,7 @@ clause_sides_match_join(RestrictInfo *rinfo, Relids outerrelids,
  * above the join.
  */
 static bool
-join_is_removable(PlannerInfo *root, SpecialJoinInfo *sjinfo)
+leftjoin_is_removable(PlannerInfo *root, SpecialJoinInfo *sjinfo)
 {
 	int			innerrelid;
 	RelOptInfo *innerrel;
@@ -253,8 +255,7 @@ join_is_removable(PlannerInfo *root, SpecialJoinInfo *sjinfo)
 	}
 
 	return is_innerrel_unique_for(root, joinrelids, sjinfo->min_lefthand,
-								  innerrel, sjinfo->jointype, innerrel->joininfo,
-								  NULL /*unique_index*/);
+								  innerrel, sjinfo->jointype, innerrel->joininfo);
 }
 
 /*
@@ -339,7 +340,8 @@ remove_rel_from_query(PlannerInfo *root, int relid, Relids joinrelids)
 	 * joinrelids.  However, a PHV used at a partner rel could not have the
 	 * target rel in ph_eval_at, so we check that while deciding whether to
 	 * remove or just update the PHV.  There is no corresponding test in
-	 * join_is_removable because it doesn't need to distinguish those cases.
+	 * leftjoin_is_removable because it doesn't need to distinguish those
+	 * cases.
 	 */
 	for (l = list_head(root->placeholder_list); l != NULL; l = nextl)
 	{
@@ -526,7 +528,7 @@ reduce_unique_semijoins(PlannerInfo *root)
 		/* Test whether the innerrel is unique for those clauses. */
 		if (!innerrel_is_unique(root,
 								joinrelids, sjinfo->min_lefthand, innerrel,
-								JOIN_SEMI, restrictlist, true, NULL /*index_info*/))
+								JOIN_SEMI, restrictlist, true))
 			continue;
 
 		/* OK, remove the SpecialJoinInfo from the list. */
@@ -601,17 +603,10 @@ rel_supports_distinctness(PlannerInfo *root, RelOptInfo *rel)
  * Note that the passed-in clause_list may be destructively modified!  This
  * is OK for current uses, because the clause_list is built by the caller for
  * the sole purpose of passing to this function.
- *
- * If unique_index is not null, it is set to point to the index that guarantees
- * uniqueness for a base relation.
  */
 static bool
-rel_is_distinct_for(PlannerInfo *root, RelOptInfo *rel, List *clause_list,
-					UniqueRelInfo **unique_info)
+rel_is_distinct_for(PlannerInfo *root, RelOptInfo *rel, List *clause_list)
 {
-	if (unique_info)
-		*unique_info = NULL;
-
 	/*
 	 * We could skip a couple of tests here if we assume all callers checked
 	 * rel_supports_distinctness first, but it doesn't seem worth taking any
@@ -626,8 +621,8 @@ rel_is_distinct_for(PlannerInfo *root, RelOptInfo *rel, List *clause_list,
 		 * relation_has_unique_index_for automatically adds any usable
 		 * restriction clauses for the rel, so we needn't do that here.
 		 */
-		return relation_has_unique_index_for(root, rel, clause_list, NIL, NIL,
-											 unique_info);
+		if (relation_has_unique_index_for(root, rel, clause_list, NIL, NIL))
+			return true;
 	}
 	else if (rel->rtekind == RTE_SUBQUERY)
 	{
@@ -931,10 +926,6 @@ distinct_col_search(int colno, List *colnos, List *opids)
  * heuristic about whether to cache negative answers; it should be "true"
  * if making an inquiry that is not part of the normal bottom-up join search
  * sequence.
- *
- * If index_info_out is not null, it is set to point to a new UniqueRelInfo
- * allocated in root memory context, that describes the index that guarantees
- * uniqueness.
  */
 bool
 innerrel_is_unique(PlannerInfo *root,
@@ -943,23 +934,12 @@ innerrel_is_unique(PlannerInfo *root,
 				   RelOptInfo *innerrel,
 				   JoinType jointype,
 				   List *restrictlist,
-				   bool force_cache,
-				   UniqueRelInfo **unique_info_out)
+				   bool force_cache)
 {
 	MemoryContext old_context;
 	ListCell   *lc;
-	UniqueRelInfo *unique_info;
-
-	if (unique_info_out)
-		*unique_info_out = NULL;
 
-	/*
-	 * It is possible to prove uniqueness even in the absence of joinclauses,
-	 * just from baserestrictinfos alone. However, in these cases the inner
-	 * relation returns one row at most, so join removal won't give much
-	 * benefit. It seems better to save some planning time by ignoring these
-	 * cases.
-	 */
+	/* Certainly can't prove uniqueness when there are no joinclauses */
 	if (restrictlist == NIL)
 		return false;
 
@@ -979,14 +959,10 @@ innerrel_is_unique(PlannerInfo *root,
 	 */
 	foreach(lc, innerrel->unique_for_rels)
 	{
-		unique_info = (UniqueRelInfo *) lfirst(lc);
+		Relids		unique_for_rels = (Relids) lfirst(lc);
 
-		if (bms_is_subset(unique_info->outerrelids, outerrelids))
-		{
-			if (unique_info_out)
-				*unique_info_out = unique_info;
+		if (bms_is_subset(unique_for_rels, outerrelids))
 			return true;		/* Success! */
-		}
 	}
 
 	/*
@@ -1003,7 +979,7 @@ innerrel_is_unique(PlannerInfo *root,
 
 	/* No cached information, so try to make the proof. */
 	if (is_innerrel_unique_for(root, joinrelids, outerrelids, innerrel,
-							   jointype, restrictlist, &unique_info))
+							   jointype, restrictlist))
 	{
 		/*
 		 * Cache the positive result for future probes, being sure to keep it
@@ -1016,15 +992,10 @@ innerrel_is_unique(PlannerInfo *root,
 		 * supersets of them anyway.
 		 */
 		old_context = MemoryContextSwitchTo(root->planner_cxt);
-		if (!unique_info)
-			unique_info = makeNode(UniqueRelInfo);
-		unique_info->outerrelids = bms_copy(outerrelids);
-		innerrel->unique_for_rels = lappend(innerrel->unique_for_rels, unique_info);
+		innerrel->unique_for_rels = lappend(innerrel->unique_for_rels,
+											bms_copy(outerrelids));
 		MemoryContextSwitchTo(old_context);
 
-		if (unique_info_out)
-			*unique_info_out = unique_info;
-
 		return true;			/* Success! */
 	}
 	else
@@ -1070,15 +1041,11 @@ is_innerrel_unique_for(PlannerInfo *root,
 					   Relids outerrelids,
 					   RelOptInfo *innerrel,
 					   JoinType jointype,
-					   List *restrictlist,
-					   UniqueRelInfo **unique_info)
+					   List *restrictlist)
 {
 	List	   *clause_list = NIL;
 	ListCell   *lc;
 
-	if (unique_info)
-		*unique_info = NULL;
-
 	/*
 	 * Search for mergejoinable clauses that constrain the inner rel against
 	 * the outer rel.  If an operator is mergejoinable then it behaves like
@@ -1116,7 +1083,7 @@ is_innerrel_unique_for(PlannerInfo *root,
 	}
 
 	/* Let rel_is_distinct_for() do the hard work */
-	return rel_is_distinct_for(root, innerrel, clause_list, unique_info);
+	return rel_is_distinct_for(root, innerrel, clause_list);
 }
 
 typedef struct
@@ -1589,53 +1556,72 @@ remove_self_join_rel(UsjScratch *scratch, Relids joinrelids, List *joinclauses,
 }
 
 /*
- * Test whether the relations are joined on the same unique column.
+ * split_selfjoin_quals
+ *		Processes 'joinquals' building two lists, one with a list of quals
+ *		where the columns/exprs on either side of the join match and another
+ *		list containing the remaining quals.
+ *
+ * 'joinquals' must only contain quals for a RTE_RELATION being joined to
+ * itself.
  */
-static bool
-is_unique_self_join(PlannerInfo *root, Relids joinrelids, RelOptInfo *outer,
-					RelOptInfo *inner, List *restrictlist)
+static void
+split_selfjoin_quals(PlannerInfo *root, List *joinquals, List **selfjoinquals,
+					 List **otherjoinquals)
 {
-	UniqueRelInfo *outerinfo = NULL;
-	UniqueRelInfo *innerinfo = NULL;
-	List *outerValues, *innerValues;
+	ListCell *lc;
+	List	 *sjoinquals = NIL;
+	List	 *rjoinquals = NIL;
 
-	innerrel_is_unique(root, joinrelids, inner->relids,
-					   outer, JOIN_INNER, restrictlist, true, &outerinfo);
-	if (!outerinfo || !outerinfo->index)
-		return false;
+	foreach(lc, joinquals)
+	{
+		RestrictInfo   *rinfo = (RestrictInfo *) lfirst(lc);
+		OpExpr		   *expr;
+		Expr		   *leftexpr;
+		Expr		   *rightexpr;
 
-	innerrel_is_unique(root, joinrelids, outer->relids,
-					   inner, JOIN_INNER, restrictlist, true, &innerinfo);
-	if (!innerinfo || !innerinfo->index)
-		return false;
+		if (bms_num_members(rinfo->clause_relids) != 2)
+			continue;
 
-	/* We must have the same unique index for both relations. */
-	if (outerinfo->index->indexoid != innerinfo->index->indexoid)
-		return false;
+		expr = (OpExpr *) rinfo->clause;
 
-	/*
-	 * We have proven that for both relations, the same unique index guarantees
-	 * that there is at most one row where columns equal given values. These
-	 * values must be the same for both relations, or else we won't match the
-	 * same row on each side of join. A value may be either Const or Var of some
-	 * other relation. For the purposes of this proof, the Vars of the inner and
-	 * outer relation are the same, so we replace outer varno with inner and
-	 * compare the column values using equal().
-	 */
-	innerValues = copyObject(innerinfo->column_values);
-	outerValues = copyObject(outerinfo->column_values);
-	change_varno((Expr *) innerValues, outer->relid, inner->relid);
-	change_varno((Expr *) outerValues, outer->relid, inner->relid);
-	if (!equal(outerValues, innerValues))
-	{
-		list_free_deep(outerValues);
-		list_free_deep(innerValues);
-		return false;
+		if (!IsA(expr, OpExpr) || list_length(expr->args) != 2)
+			continue;
+
+		leftexpr = linitial(expr->args);
+		rightexpr = lsecond(expr->args);
+
+		/* Can't match of the exprs are not of the same type */
+		if (leftexpr->type != rightexpr->type)
+			continue;
+
+		/* Easy case, both exprs are Vars */
+		if (IsA(leftexpr, Var))
+		{
+			Var *leftvar = (Var *) leftexpr;
+			Var *rightvar = (Var *) rightexpr;
+
+			Assert(leftvar->varlevelsup == 0);
+			Assert(rightvar->varlevelsup == 0);
+
+			/*
+			 * Ensure the caller didn't pass us any join quals that are not
+			 * self join quals.
+			 */
+			Assert(root->simple_rte_array[leftvar->varno]->relid ==
+				   root->simple_rte_array[rightvar->varno]->relid);
+
+			if (leftvar->varattno == rightvar->varattno)
+				sjoinquals = lappend(sjoinquals, rinfo);
+			else
+				rjoinquals = lappend(rjoinquals, rinfo);
+
+		}
+
+		/* TODO handle complex exprs by replacing varnos on RHS expr */
 	}
-	list_free_deep(outerValues);
-	list_free_deep(innerValues);
 
-	return true;
+	*selfjoinquals = sjoinquals;
+	*otherjoinquals = rjoinquals;
 }
 
 /*
@@ -1662,7 +1648,9 @@ remove_self_joins_one_group(UsjScratch *scratch, Index *relids, int n)
 		for (i = o + 1; i < n; i++)
 		{
 			RelOptInfo *inner = root->simple_rel_array[relids[i]];
-			List *restrictlist;
+			List	   *restrictlist;
+			List	   *selfjoinquals;
+			List	   *otherjoinquals;
 
 			/* A sanity check: the relations have the same Oid. */
 			Assert(root->simple_rte_array[relids[i]]->relid
@@ -1688,8 +1676,24 @@ remove_self_joins_one_group(UsjScratch *scratch, Index *relids, int n)
 			/* Is it a unique self join? */
 			restrictlist = build_joinrel_restrictlist(root, joinrelids, outer,
 													  inner);
-			if (!is_unique_self_join(root, joinrelids, outer, inner,
-									 restrictlist))
+
+			/*
+			 * Process restrictlist to seperate out the self join quals from
+			 * the other quals. e.g x = x goes to selfjoinquals and a = b to
+			 * otherjoinquals.
+			 */
+			split_selfjoin_quals(root, restrictlist, &selfjoinquals,
+								 &otherjoinquals);
+
+			/*
+			 * Determine if the inner table can duplicate outer rows.  We must
+			 * bypass the unique rel cache here since we're possibly using a
+			 * subset of join quals. We can use 'force_cache' = true when all
+			 * join quals are selfjoin quals.  Otherwise we could end up
+			 * putting false negatives in the cache.
+			 */
+			if (!innerrel_is_unique(root, joinrelids, inner->relids,
+				outer, JOIN_INNER, selfjoinquals, list_length(otherjoinquals) == 0))
 				continue;
 
 			/*
diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c
index 493f4255dd..169e51e792 100644
--- a/src/backend/optimizer/util/pathnode.c
+++ b/src/backend/optimizer/util/pathnode.c
@@ -1578,8 +1578,7 @@ create_unique_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath,
 	if (rel->rtekind == RTE_RELATION && sjinfo->semi_can_btree &&
 		relation_has_unique_index_for(root, rel, NIL,
 									  sjinfo->semi_rhs_exprs,
-									  sjinfo->semi_operators,
-									  NULL /*index_info*/))
+									  sjinfo->semi_operators))
 	{
 		pathnode->umethod = UNIQUE_PATH_NOOP;
 		pathnode->path.rows = rel->rows;
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index 59ca1fe40e..ffb4cd4bcc 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -272,7 +272,6 @@ typedef enum NodeTag
 	T_RollupData,
 	T_GroupingSetData,
 	T_StatisticExtInfo,
-	T_UniqueRelInfo,
 
 	/*
 	 * TAGS FOR MEMORY NODES (memnodes.h)
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index 0592b64bb7..253e0b7e48 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -522,11 +522,8 @@ typedef struct PartitionSchemeData *PartitionScheme;
  * populate these fields, for base rels; but someday they might be used for
  * join rels too:
  *
- *		unique_for_rels - list of UniqueRelInfos, each of them recording
- * 					a set of other rels for which this one has been proven
- *					unique. If this is a baserel that is made unique by an
- * 					index, UniqueRelInfo also stores the information about
- * 					that index.
+ *		unique_for_rels - list of Relid sets, each one being a set of other
+ *					rels for which this one has been proven unique
  *		non_unique_for_rels - list of Relid sets, each one being a set of
  *					other rels for which we have tried and failed to prove
  *					this one unique
@@ -2474,19 +2471,4 @@ typedef struct JoinCostWorkspace
 	double		inner_rows_total;
 } JoinCostWorkspace;
 
-/*
- * UniqueRelInfo records a fact that a relation is unique when being joined
- * to other relation(s) specified by outerrelids. If the uniqueness is
- * guaranteed by a unique index, this index is also saved. The values that
- * constrain index columns, be it Vars of outer relations or Consts, are saved
- * to column_values list.
- */
-typedef struct UniqueRelInfo
-{
-	NodeTag		tag;
-	Relids		outerrelids;
-	IndexOptInfo *index;
-	List	   *column_values;
-} UniqueRelInfo;
-
 #endif							/* PATHNODES_H */
diff --git a/src/include/optimizer/paths.h b/src/include/optimizer/paths.h
index 4260227b9f..36d12bc376 100644
--- a/src/include/optimizer/paths.h
+++ b/src/include/optimizer/paths.h
@@ -70,11 +70,9 @@ extern void debug_print_rel(PlannerInfo *root, RelOptInfo *rel);
  *	  routines to generate index paths
  */
 extern void create_index_paths(PlannerInfo *root, RelOptInfo *rel);
-
 extern bool relation_has_unique_index_for(PlannerInfo *root, RelOptInfo *rel,
 							  List *restrictlist,
-							  List *exprlist, List *oprlist,
-							  UniqueRelInfo **info);
+							  List *exprlist, List *oprlist);
 extern bool indexcol_is_bool_constant_for_query(IndexOptInfo *index,
 									int indexcol);
 extern bool match_index_to_operand(Node *operand, int indexcol,
diff --git a/src/include/optimizer/planmain.h b/src/include/optimizer/planmain.h
index 252b8da686..15fa476907 100644
--- a/src/include/optimizer/planmain.h
+++ b/src/include/optimizer/planmain.h
@@ -103,8 +103,7 @@ extern bool query_is_distinct_for(Query *query, List *colnos, List *opids);
 
 extern bool innerrel_is_unique(PlannerInfo *root,
 				   Relids joinrelids, Relids outerrelids, RelOptInfo *innerrel,
-				   JoinType jointype, List *restrictlist, bool force_cache,
-				   UniqueRelInfo **unique_info);
+				   JoinType jointype, List *restrictlist, bool force_cache);
 
 extern void remove_useless_self_joins(PlannerInfo *root, List **jointree,
 									  List *tlist);
diff --git a/src/test/regress/expected/join.out b/src/test/regress/expected/join.out
index 38e3842278..71d6cf7dc7 100644
--- a/src/test/regress/expected/join.out
+++ b/src/test/regress/expected/join.out
@@ -4365,13 +4365,11 @@ explain (costs off)
 select p.* from
   (parent p left join child c on (p.k = c.k)) join parent x on p.k = x.k
   where p.k = 1 and p.k = 2;
-                   QUERY PLAN                   
-------------------------------------------------
+        QUERY PLAN        
+--------------------------
  Result
    One-Time Filter: false
-   ->  Index Scan using parent_pkey on parent x
-         Index Cond: (k = 1)
-(4 rows)
+(2 rows)
 
 -- bug 5255: this is not optimizable by join removal
 begin;
@@ -4674,27 +4672,19 @@ explain (costs off) select 1 from
 
 reset join_collapse_limit;
 reset enable_seqscan;
--- If index conditions are different for each side, we won't select the same
--- row on both sides, so the join can't be removed.
+-- We can remove the join even if we find the join can't duplicate rows and
+-- the base quals of each side are different.  In the following case we end up
+-- moving quals over to s1 to make it so it can't match any rows.
 create table sl(a int, b int);
 create unique index sl_ab on sl(a, b);
 explain (costs off)
 select * from sl t1, sl t2
 where t1.a = t2.a and t1.b = 1 and t2.b = 2;
-                  QUERY PLAN                  
-----------------------------------------------
- Nested Loop
-   Join Filter: (t1.a = t2.a)
-   ->  Bitmap Heap Scan on sl t1
-         Recheck Cond: (b = 1)
-         ->  Bitmap Index Scan on sl_ab
-               Index Cond: (b = 1)
-   ->  Materialize
-         ->  Bitmap Heap Scan on sl t2
-               Recheck Cond: (b = 2)
-               ->  Bitmap Index Scan on sl_ab
-                     Index Cond: (b = 2)
-(11 rows)
+                       QUERY PLAN                        
+---------------------------------------------------------
+ Index Only Scan using sl_ab on sl t2
+   Index Cond: ((a IS NOT NULL) AND (b = 2) AND (b = 1))
+(2 rows)
 
 reset enable_hashjoin;
 reset enable_mergejoin;
diff --git a/src/test/regress/sql/join.sql b/src/test/regress/sql/join.sql
index 001b41b8b7..262b3988f8 100644
--- a/src/test/regress/sql/join.sql
+++ b/src/test/regress/sql/join.sql
@@ -1651,8 +1651,9 @@ explain (costs off) select 1 from
 reset join_collapse_limit;
 reset enable_seqscan;
 
--- If index conditions are different for each side, we won't select the same
--- row on both sides, so the join can't be removed.
+-- We can remove the join even if we find the join can't duplicate rows and
+-- the base quals of each side are different.  In the following case we end up
+-- moving quals over to s1 to make it so it can't match any rows.
 create table sl(a int, b int);
 create unique index sl_ab on sl(a, b);
 
