diff --git a/doc/src/sgml/ref/reindex.sgml b/doc/src/sgml/ref/reindex.sgml
index cabae19..096960d 100644
--- a/doc/src/sgml/ref/reindex.sgml
+++ b/doc/src/sgml/ref/reindex.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-REINDEX { INDEX | TABLE | DATABASE | SYSTEM } <replaceable class="PARAMETER">name</replaceable> [ FORCE ]
+REINDEX { INDEX | TABLE | SCHEMA | DATABASE | SYSTEM } <replaceable class="PARAMETER">name</replaceable> [ FORCE ]
 </synopsis>
  </refsynopsisdiv>
 
@@ -101,6 +101,19 @@ REINDEX { INDEX | TABLE | DATABASE | SYSTEM } <replaceable class="PARAMETER">nam
    </varlistentry>
 
    <varlistentry>
+    <term><literal>SCHEMA</literal></term>
+    <listitem>
+     <para>
+      Recreate all indexes of the specified schema.  If the table has a
+      secondary <quote>TOAST</> table, that is reindexed as well.
+      Indexes on shared system catalogs are also processed.
+      This form of <command>REINDEX</command> cannot be executed inside a
+      transaction block.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><literal>DATABASE</literal></term>
     <listitem>
      <para>
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 12b4ac7..d00f663 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -1777,34 +1777,58 @@ ReindexTable(RangeVar *relation)
 }
 
 /*
- * ReindexDatabase
- *		Recreate indexes of a database.
+ * ReindexObject
+ *		Recreate indexes of a database or schema.
  *
+ * kind means the type of object, database or schema.
  * To reduce the probability of deadlocks, each table is reindexed in a
  * separate transaction, so we can release the lock on it right away.
  * That means this must not be called within a user transaction block!
  */
 Oid
-ReindexDatabase(const char *databaseName, bool do_system, bool do_user)
+ReindexObject(const char *objectName, ReindexObjectType kind)
 {
+	Oid			objectOid;
 	Relation	relationRelation;
 	HeapScanDesc scan;
+	ScanKeyData	*key = NULL;
 	HeapTuple	tuple;
 	MemoryContext private_context;
 	MemoryContext old;
 	List	   *relids = NIL;
 	ListCell   *l;
+	bool do_database = (kind >= REINDEX_OBJECT_SYSTEM);
+	bool do_system = false;
+	bool do_user = false;
+	int	nkeys;
 
-	AssertArg(databaseName);
+	AssertArg(objectName);
+	Assert(kind >= REINDEX_OBJECT_SCHEMA && kind <= REINDEX_OBJECT_DATABASE);
 
-	if (strcmp(databaseName, get_database_name(MyDatabaseId)) != 0)
+	/* Get OID of object for result */
+	if (do_database)
+		objectOid = MyDatabaseId;
+	else
+		objectOid = get_namespace_oid(objectName, false);
+
+	if (!do_database)
+	{
+		do_system = IsSystemNamespace(objectOid);
+		do_user = !do_system;
+	}
+
+	if (do_database && strcmp(objectName, get_database_name(MyDatabaseId)) != 0)
 		ereport(ERROR,
 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 				 errmsg("can only reindex the currently open database")));
 
-	if (!pg_database_ownercheck(MyDatabaseId, GetUserId()))
+	if (do_database && !pg_database_ownercheck(MyDatabaseId, GetUserId()))
 		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
-					   databaseName);
+					   objectName);
+
+	if (!do_database && !pg_namespace_ownercheck(objectOid, GetUserId()))
+		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_NAMESPACE,
+					   objectName);
 
 	/*
 	 * Create a memory context that will survive forced transaction commits we
@@ -1813,7 +1837,8 @@ ReindexDatabase(const char *databaseName, bool do_system, bool do_user)
 	 * abort cleanup logic.
 	 */
 	private_context = AllocSetContextCreate(PortalContext,
-											"ReindexDatabase",
+											(do_database) ?
+											"ReindexDatabase" : "ReindexSchema",
 											ALLOCSET_DEFAULT_MINSIZE,
 											ALLOCSET_DEFAULT_INITSIZE,
 											ALLOCSET_DEFAULT_MAXSIZE);
@@ -1831,6 +1856,23 @@ ReindexDatabase(const char *databaseName, bool do_system, bool do_user)
 		MemoryContextSwitchTo(old);
 	}
 
+	/* For schema, we search target relations by relnamespce and relkind */
+	if (!do_database)
+	{
+		key = palloc(sizeof(ScanKeyData) * 2);
+		ScanKeyInit(&key[0],
+					Anum_pg_class_relnamespace,
+					BTEqualStrategyNumber, F_OIDEQ,
+					ObjectIdGetDatum(objectOid));
+		ScanKeyInit(&key[1],
+					Anum_pg_class_relkind,
+					BTEqualStrategyNumber, F_CHAREQ,
+					'r');
+		nkeys = 2;
+	}
+	else
+		nkeys = 0;
+
 	/*
 	 * Scan pg_class to build a list of the relations we need to reindex.
 	 *
@@ -1838,7 +1880,7 @@ ReindexDatabase(const char *databaseName, bool do_system, bool do_user)
 	 * rels will be processed indirectly by reindex_relation).
 	 */
 	relationRelation = heap_open(RelationRelationId, AccessShareLock);
-	scan = heap_beginscan_catalog(relationRelation, 0, NULL);
+	scan = heap_beginscan_catalog(relationRelation, nkeys, key);
 	while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
 	{
 		Form_pg_class classtuple = (Form_pg_class) GETSTRUCT(tuple);
@@ -1899,5 +1941,5 @@ ReindexDatabase(const char *databaseName, bool do_system, bool do_user)
 
 	MemoryContextDelete(private_context);
 
-	return MyDatabaseId;
+	return objectOid;
 }
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index bd180e7..da3dc31 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -404,7 +404,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 %type <boolean> copy_from opt_program
 
 %type <ival>	opt_column event cursor_options opt_hold opt_set_data
-%type <objtype>	reindex_type drop_type comment_type security_label_type
+%type <objtype>	reindex_type reindex_object drop_type comment_type security_label_type
 
 %type <node>	fetch_args limit_clause select_limit_value
 				offset_clause select_offset_value
@@ -7197,31 +7197,25 @@ ReindexStmt:
 					n->name = NULL;
 					$$ = (Node *)n;
 				}
-			| REINDEX SYSTEM_P name opt_force
+			| REINDEX reindex_object name opt_force
 				{
 					ReindexStmt *n = makeNode(ReindexStmt);
-					n->kind = OBJECT_DATABASE;
-					n->name = $3;
-					n->relation = NULL;
-					n->do_system = true;
-					n->do_user = false;
-					$$ = (Node *)n;
-				}
-			| REINDEX DATABASE name opt_force
-				{
-					ReindexStmt *n = makeNode(ReindexStmt);
-					n->kind = OBJECT_DATABASE;
+					n->kind = $2;
 					n->name = $3;
 					n->relation = NULL;
-					n->do_system = true;
-					n->do_user = true;
 					$$ = (Node *)n;
 				}
 		;
 
 reindex_type:
-			INDEX									{ $$ = OBJECT_INDEX; }
-			| TABLE									{ $$ = OBJECT_TABLE; }
+			INDEX									{ $$ = REINDEX_OBJECT_INDEX; }
+			| TABLE									{ $$ = REINDEX_OBJECT_TABLE; }
+		;
+
+reindex_object:
+			SYSTEM_P								{ $$ = REINDEX_OBJECT_SYSTEM; }
+			| SCHEMA								{ $$ = REINDEX_OBJECT_SCHEMA; }
+			| DATABASE								{ $$ = REINDEX_OBJECT_DATABASE; }
 		;
 
 opt_force:	FORCE									{  $$ = TRUE; }
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 58f78ce..f89d6cc 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -749,14 +749,16 @@ standard_ProcessUtility(Node *parsetree,
 				PreventCommandDuringRecovery("REINDEX");
 				switch (stmt->kind)
 				{
-					case OBJECT_INDEX:
+					case REINDEX_OBJECT_INDEX:
 						ReindexIndex(stmt->relation);
 						break;
-					case OBJECT_TABLE:
-					case OBJECT_MATVIEW:
+					case REINDEX_OBJECT_TABLE:
+					case REINDEX_OBJECT_MATVIEW:
 						ReindexTable(stmt->relation);
 						break;
-					case OBJECT_DATABASE:
+					case REINDEX_OBJECT_SCHEMA:
+					case REINDEX_OBJECT_SYSTEM:
+					case REINDEX_OBJECT_DATABASE:
 
 						/*
 						 * This cannot run inside a user transaction block; if
@@ -765,9 +767,10 @@ standard_ProcessUtility(Node *parsetree,
 						 * intended effect!
 						 */
 						PreventTransactionChain(isTopLevel,
-												"REINDEX DATABASE");
-						ReindexDatabase(stmt->name,
-										stmt->do_system, stmt->do_user);
+												(stmt->kind == REINDEX_OBJECT_DATABASE) ?
+												"REINDEX DATABASE" : ((stmt->kind == REINDEX_OBJECT_SCHEMA) ?
+																	  "REINDEX SCHEMA" : "REINDEX SYSTEM"));
+						ReindexObject(stmt->name, stmt->kind);
 						break;
 					default:
 						elog(ERROR, "unrecognized object type: %d",
diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index 8c85425..380c579 100644
--- a/src/bin/psql/tab-complete.c
+++ b/src/bin/psql/tab-complete.c
@@ -3330,7 +3330,7 @@ psql_completion(const char *text, int start, int end)
 	else if (pg_strcasecmp(prev_wd, "REINDEX") == 0)
 	{
 		static const char *const list_REINDEX[] =
-		{"TABLE", "INDEX", "SYSTEM", "DATABASE", NULL};
+			{"TABLE", "INDEX", "SYSTEM", "SCHEMA", "DATABASE", NULL};
 
 		COMPLETE_WITH_LIST(list_REINDEX);
 	}
@@ -3340,6 +3340,8 @@ psql_completion(const char *text, int start, int end)
 			COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm, NULL);
 		else if (pg_strcasecmp(prev_wd, "INDEX") == 0)
 			COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, NULL);
+		else if (pg_strcasecmp(prev_wd, "SCHEMA") == 0 )
+			COMPLETE_WITH_QUERY(Query_for_list_of_schemas);
 		else if (pg_strcasecmp(prev_wd, "SYSTEM") == 0 ||
 				 pg_strcasecmp(prev_wd, "DATABASE") == 0)
 			COMPLETE_WITH_QUERY(Query_for_list_of_databases);
diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h
index 0ebdbc1..f6210d3 100644
--- a/src/include/commands/defrem.h
+++ b/src/include/commands/defrem.h
@@ -30,8 +30,7 @@ extern Oid DefineIndex(Oid relationId,
 			bool quiet);
 extern Oid	ReindexIndex(RangeVar *indexRelation);
 extern Oid	ReindexTable(RangeVar *relation);
-extern Oid ReindexDatabase(const char *databaseName,
-				bool do_system, bool do_user);
+extern Oid ReindexObject(const char *databaseName, ReindexObjectType kind);
 extern char *makeObjectName(const char *name1, const char *name2,
 			   const char *label);
 extern char *ChooseRelationName(const char *name1, const char *name2,
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 3e4f815..4984a55 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -2721,10 +2721,20 @@ typedef struct ConstraintsSetStmt
  *		REINDEX Statement
  * ----------------------
  */
+typedef enum ReindexObjectType
+{
+	REINDEX_OBJECT_INDEX,    /* index */
+	REINDEX_OBJECT_TABLE,    /* table */
+	REINDEX_OBJECT_MATVIEW,  /* materialized view */
+	REINDEX_OBJECT_SCHEMA,   /* schema */
+	REINDEX_OBJECT_SYSTEM,   /* system catalog */
+	REINDEX_OBJECT_DATABASE /* database */
+} ReindexObjectType;
+
 typedef struct ReindexStmt
 {
 	NodeTag		type;
-	ObjectType	kind;			/* OBJECT_INDEX, OBJECT_TABLE, etc. */
+	ReindexObjectType	kind;	/* REINDEX_OBJECT_INDEX, REINDEX_OBJECT_TABLE, etc. */
 	RangeVar   *relation;		/* Table or index to reindex */
 	const char *name;			/* name of database to reindex */
 	bool		do_system;		/* include system tables in database case */
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 3ecb238..895ce93 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2831,3 +2831,30 @@ explain (costs off)
    Index Cond: ((thousand = 1) AND (tenthous = 1001))
 (2 rows)
 
+--
+-- Reindex All In Schema
+--
+REINDEX SCHEMA tobereindexed; -- fail because schema doesn't exists
+ERROR:  schema "tobereindexed" does not exist
+CREATE SCHEMA tobereindexed;
+CREATE TABLE tobereindexed.table1(col1 SERIAL PRIMARY KEY);
+CREATE TABLE tobereindexed.table2(col1 SERIAL PRIMARY KEY, col2 VARCHAR(100) NOT NULL);
+CREATE INDEX ON tobereindexed.table2(col2);
+REINDEX SCHEMA tobereindexed;
+NOTICE:  table "tobereindexed.table1" was reindexed
+NOTICE:  table "tobereindexed.table2" was reindexed
+BEGIN;
+REINDEX SCHEMA tobereindexed;
+ERROR:  REINDEX SCHEMA cannot run inside a transaction block
+END;
+-- Try to reindex by unprivileged user
+CREATE ROLE reindexuser login;
+SET SESSION ROLE reindexuser;
+REINDEX SCHEMA tobereindexed;
+ERROR:  must be owner of schema tobereindexed
+-- clean up
+\c -
+DROP ROLE reindexuser;
+DROP TABLE tobereindexed.table2;
+DROP TABLE tobereindexed.table1;
+DROP SCHEMA tobereindexed;
diff --git a/src/test/regress/sql/create_index.sql b/src/test/regress/sql/create_index.sql
index e837676..544c31e 100644
--- a/src/test/regress/sql/create_index.sql
+++ b/src/test/regress/sql/create_index.sql
@@ -964,3 +964,28 @@ RESET enable_indexscan;
 
 explain (costs off)
   select * from tenk1 where (thousand, tenthous) in ((1,1001), (null,null));
+
+--
+-- Reindex All In Schema
+--
+REINDEX SCHEMA tobereindexed; -- fail because schema doesn't exists
+CREATE SCHEMA tobereindexed;
+CREATE TABLE tobereindexed.table1(col1 SERIAL PRIMARY KEY);
+CREATE TABLE tobereindexed.table2(col1 SERIAL PRIMARY KEY, col2 VARCHAR(100) NOT NULL);
+CREATE INDEX ON tobereindexed.table2(col2);
+REINDEX SCHEMA tobereindexed;
+BEGIN;
+REINDEX SCHEMA tobereindexed;
+END;
+
+-- Try to reindex by unprivileged user
+CREATE ROLE reindexuser login;
+SET SESSION ROLE reindexuser;
+REINDEX SCHEMA tobereindexed;
+
+-- clean up
+\c -
+DROP ROLE reindexuser;
+DROP TABLE tobereindexed.table2;
+DROP TABLE tobereindexed.table1;
+DROP SCHEMA tobereindexed;
