diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c
index 4b9be13..fcdccf1 100644
--- a/src/backend/optimizer/path/costsize.c
+++ b/src/backend/optimizer/path/costsize.c
@@ -4078,7 +4078,7 @@ get_restriction_qual_cost(PlannerInfo *root, RelOptInfo *baserel,
  *	joinrel: join relation under consideration
  *	outerrel: outer relation under consideration
  *	innerrel: inner relation under consideration
- *	jointype: if not JOIN_SEMI or JOIN_ANTI, we assume it's inner_unique
+ *	jointype: if not JOIN_SEMI or JOIN_ANTI, must be an inner_unique case
  *	sjinfo: SpecialJoinInfo relevant to this join
  *	restrictlist: join quals
  * Output parameters:
@@ -4101,14 +4101,16 @@ compute_semi_anti_join_factors(PlannerInfo *root,
 	List	   *joinquals;
 	ListCell   *l;
 
+	/* We have to do this differently for semi/anti joins vs. inner_unique */
+	if (jointype == JOIN_SEMI || jointype == JOIN_ANTI)
+	{
 	/*
 	 * In an ANTI join, we must ignore clauses that are "pushed down", since
 	 * those won't affect the match logic.  In a SEMI join, we do not
 	 * distinguish joinquals from "pushed down" quals, so just use the whole
-	 * restrictinfo list.  For other outer join types, we should consider only
-	 * non-pushed-down quals, so that this devolves to an IS_OUTER_JOIN check.
+	 * restrictinfo list.
 	 */
-	if (IS_OUTER_JOIN(jointype))
+	if (jointype == JOIN_ANTI)
 	{
 		joinquals = NIL;
 		foreach(l, restrictlist)
@@ -4128,7 +4130,7 @@ compute_semi_anti_join_factors(PlannerInfo *root,
 	jselec = clauselist_selectivity(root,
 									joinquals,
 									0,
-									(jointype == JOIN_ANTI) ? JOIN_ANTI : JOIN_SEMI,
+									jointype,
 									sjinfo);
 
 	/*
@@ -4155,7 +4157,7 @@ compute_semi_anti_join_factors(PlannerInfo *root,
 									&norm_sjinfo);
 
 	/* Avoid leaking a lot of ListCells */
-	if (IS_OUTER_JOIN(jointype))
+	if (jointype == JOIN_ANTI)
 		list_free(joinquals);
 
 	/*
@@ -4178,6 +4180,21 @@ compute_semi_anti_join_factors(PlannerInfo *root,
 	}
 	else
 		avgmatch = 1.0;
+	}
+	else
+	{
+		/*
+		 * Must be an inner_unique case.  match_count is 1 by definition, and
+		 * we can compute outer_match_frac as joinrel size / outerrel size.
+		 * For paranoia's sake, clamp that to 0..1.
+		 */
+		if (outerrel->rows > 0)
+			jselec = joinrel->rows / outerrel->rows;
+		else
+			jselec = 1.0;
+		CLAMP_PROBABILITY(jselec);
+		avgmatch = 1.0;
+	}
 
 	semifactors->outer_match_frac = jselec;
 	semifactors->match_count = avgmatch;
diff --git a/src/test/regress/expected/join.out b/src/test/regress/expected/join.out
index 593aec2..b58ca75 100644
--- a/src/test/regress/expected/join.out
+++ b/src/test/regress/expected/join.out
@@ -5712,15 +5712,14 @@ select * from j1 inner join j3 on j1.id = j3.id;
 -----------------------------------
  Hash Join
    Output: j1.id, j3.id
-   Inner Unique: true
-   Hash Cond: (j3.id = j1.id)
-   ->  Seq Scan on public.j3
-         Output: j3.id
-   ->  Hash
+   Hash Cond: (j1.id = j3.id)
+   ->  Seq Scan on public.j1
          Output: j1.id
-         ->  Seq Scan on public.j1
-               Output: j1.id
-(10 rows)
+   ->  Hash
+         Output: j3.id
+         ->  Seq Scan on public.j3
+               Output: j3.id
+(9 rows)
 
 -- ensure left join is marked as unique
 explain (verbose, costs off)
