diff --git a/src/backend/commands/matview.c b/src/backend/commands/matview.c
index 869c586..fbf6af8 100644
--- a/src/backend/commands/matview.c
+++ b/src/backend/commands/matview.c
@@ -216,6 +216,46 @@ ExecRefreshMatView(RefreshMatViewStmt *stmt, const char *queryString,
 			 "the rule for materialized view \"%s\" is not a single action",
 			 RelationGetRelationName(matviewRel));
 
+	/* When CONCURRENTLY refresh, we need at least one unique index. */
+	if (concurrent)
+	{
+		List		*indexoidlist = RelationGetIndexList(matviewRel);
+		ListCell 	*indexoidscan;
+		bool		hasUniqueIndex = false;
+
+		foreach(indexoidscan, indexoidlist)
+		{
+			Oid			indexoid = lfirst_oid(indexoidscan);
+			Relation	indexRel;
+			Form_pg_index	indexStruct;
+
+			indexRel = index_open(indexoid, AccessShareLock);
+			indexStruct = indexRel->rd_index;
+
+			if (indexStruct->indisunique &&
+				IndexIsValid(indexStruct) &&
+				RelationGetIndexExpressions(indexRel) == NIL &&
+				RelationGetIndexPredicate(indexRel) == NIL)
+			{
+				hasUniqueIndex = true;
+				index_close(indexRel, AccessShareLock);
+				break;
+			}
+
+			index_close(indexRel, AccessShareLock);
+		}
+
+		list_free(indexoidlist);
+
+		if (!hasUniqueIndex)
+			ereport(ERROR,
+					(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+					 errmsg("cannot refresh materialized view \"%s\" concurrently",
+							quote_qualified_identifier(get_namespace_name(RelationGetNamespace(matviewRel)),
+																		  RelationGetRelationName(matviewRel))),
+					 errhint("Create a unique index with no WHERE clause on one or more columns of the materialized view.")));
+	}
+
 	/*
 	 * The stored query was rewritten at the time of the MV definition, but
 	 * has not been scribbled on by the planner.
@@ -523,8 +563,8 @@ mv_GenerateOper(StringInfo buf, Oid opoid)
  * in the face of rows which have at least one NULL value, with all non-NULL
  * columns equal.  The behavior of NULLs on equality tests and on UNIQUE
  * indexes turns out to be quite convenient here; the tests we need to make
- * are consistent with default behavior.  If there is at least one UNIQUE
- * index on the materialized view, we have exactly the guarantee we need.
+ * are consistent with default behavior.  There must be at least one UNIQUE
+ * index on the materialized view, which is the guarantee we need.
  *
  * The temporary table used to hold the diff results contains just the TID of
  * the old record (if matched) and the ROW from the new table as a single
@@ -695,12 +735,8 @@ refresh_by_match_merge(Oid matviewOid, Oid tempOid, Oid relowner,
 
 	list_free(indexoidlist);
 
-	if (!foundUniqueIndex)
-		ereport(ERROR,
-				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-			   errmsg("cannot refresh materialized view \"%s\" concurrently",
-					  matviewname),
-				 errhint("Create a unique index with no WHERE clause on one or more columns of the materialized view.")));
+	/* We have guarantee that materialized view has at least one UNIQUE index */
+	Assert(foundUniqueIndex);
 
 	appendStringInfoString(&querybuf,
 						   " AND newdata OPERATOR(pg_catalog.*=) mv) "
