diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 98a02b27ddfd7e05e89f4ece181ced5aa60b3f83..f7d39edf6fd24961f88dd92383ea87151b97acc2 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -1770,6 +1770,7 @@ _outIndexOptInfo(StringInfo str, IndexOptInfo *node)
 	WRITE_NODE_FIELD(indextlist);
 	WRITE_BOOL_FIELD(predOK);
 	WRITE_BOOL_FIELD(unique);
+	WRITE_BOOL_FIELD(immediate);
 	WRITE_BOOL_FIELD(hypothetical);
 }
 
diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c
index 940efb38b668dac8a8e773f996efcda5267ca6c1..77df5a24ea24d67abc4b0b087960aacf76cb012d 100644
--- a/src/backend/optimizer/path/indxpath.c
+++ b/src/backend/optimizer/path/indxpath.c
@@ -2277,10 +2277,11 @@ relation_has_unique_index_for(PlannerInfo *root, RelOptInfo *rel,
 		int			c;
 
 		/*
-		 * If the index is not unique or if it's a partial index that doesn't
-		 * match the query, it's useless here.
+		 * If the index is not unique, or not immediately enforced, or if it's
+		 * a partial index that doesn't match the query, it's useless here.
 		 */
-		if (!ind->unique || (ind->indpred != NIL && !ind->predOK))
+		if (!ind->unique || !ind->immediate ||
+			(ind->indpred != NIL && !ind->predOK))
 			continue;
 
 		/*
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index bb8095224247694b0630ea6ea7947e980dbc45f5..de629e93c9adf6f925a49010dae2d82c2ca97181 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -324,6 +324,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
 
 			info->predOK = false;		/* set later in indxpath.c */
 			info->unique = index->indisunique;
+			info->immediate = index->indimmediate;
 			info->hypothetical = false;
 
 			/*
@@ -1076,6 +1077,11 @@ join_selectivity(PlannerInfo *root,
  * Detect whether there is a unique index on the specified attribute
  * of the specified relation, thus allowing us to conclude that all
  * the (non-null) values of the attribute are distinct.
+ *
+ * This function does not check the index's indimmediate property, which
+ * means that uniqueness may transiently fail to hold intra-transaction.
+ * That's appropriate when we are making statistical estimates, but beware
+ * of using this for any correctness proofs.
  */
 bool
 has_unique_index(RelOptInfo *rel, AttrNumber attno)
diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c
index 96946281dabe1d0f2db82878d536043733b4a4ff..f05cc4f87ee51647ffe3a10fb55c33aecb7c9959 100644
--- a/src/backend/utils/adt/selfuncs.c
+++ b/src/backend/utils/adt/selfuncs.c
@@ -4129,7 +4129,9 @@ get_join_variables(PlannerInfo *root, List *args, SpecialJoinInfo *sjinfo,
  *		commonly the same as the exposed type of the variable argument,
  *		but can be different in binary-compatible-type cases.
  *	isunique: TRUE if we were able to match the var to a unique index,
- *		implying its values are unique for this query.
+ *		implying its values are unique for this query.  (Caution: this
+ *		should be trusted for statistical purposes only, since we do not
+ *		check indimmediate.)
  *
  * Caller is responsible for doing ReleaseVariableStats() before exiting.
  */
diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h
index 2925d7e76598d50a9bb0cdf9a4ede12338a849c4..ede97571e06ab1fd6dd5bbd7bad9b482899d52e7 100644
--- a/src/include/nodes/relation.h
+++ b/src/include/nodes/relation.h
@@ -488,6 +488,7 @@ typedef struct IndexOptInfo
 
 	bool		predOK;			/* true if predicate matches query */
 	bool		unique;			/* true if a unique index */
+	bool		immediate;		/* is uniqueness enforced immediately? */
 	bool		hypothetical;	/* true if index doesn't really exist */
 	bool		amcanorderbyop; /* does AM support order by operator result? */
 	bool		amcanreturn;	/* can AM return IndexTuples? */