From ff4941c738a5429db57aa13cacc0e126d90ee185 Mon Sep 17 00:00:00 2001
From: Alexey Kondratov <kondratov.aleksey@gmail.com>
Date: Wed, 23 Sep 2020 18:21:16 +0300
Subject: [PATCH 2/4] Refactor and reuse set_rel_tablespace()

---
 src/backend/catalog/index.c      | 70 +++++++++++++++++++++-----------
 src/backend/commands/indexcmds.c | 35 ----------------
 src/include/catalog/index.h      |  2 +
 3 files changed, 49 insertions(+), 58 deletions(-)

diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9aa9fdf291..f652459d83 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3722,24 +3722,11 @@ reindex_index(Oid indexId, bool skip_constraint_checks, char persistence,
 		params->tablespaceOid = InvalidOid;
 
 	/*
-	 * Set the new tablespace for the relation.  Do that only in the
-	 * case where the reindex caller wishes to enforce a new tablespace.
+	 * Set the new tablespace for the relation if requested.
 	 */
 	if (set_tablespace &&
-			params->tablespaceOid != iRel->rd_rel->reltablespace)
+		set_rel_tablespace(indexId, params->tablespaceOid))
 	{
-		Relation		pg_class;
-		Form_pg_class	rd_rel;
-		HeapTuple		tuple;
-
-		/* First get a modifiable copy of the relation's pg_class row */
-		pg_class = table_open(RelationRelationId, RowExclusiveLock);
-
-		tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(indexId));
-		if (!HeapTupleIsValid(tuple))
-			elog(ERROR, "cache lookup failed for relation %u", indexId);
-		rd_rel = (Form_pg_class) GETSTRUCT(tuple);
-
 		/*
 		 * Mark the relation as ready to be dropped at transaction commit,
 		 * before making visible the new tablespace change so as this won't
@@ -3747,14 +3734,6 @@ reindex_index(Oid indexId, bool skip_constraint_checks, char persistence,
 		 */
 		RelationDropStorage(iRel);
 
-		/* Update the pg_class row */
-		rd_rel->reltablespace = params->tablespaceOid;
-		CatalogTupleUpdate(pg_class, &tuple->t_self, tuple);
-
-		heap_freetuple(tuple);
-
-		table_close(pg_class, RowExclusiveLock);
-
 		RelationAssumeNewRelfilenode(iRel);
 
 		/* Make sure the reltablespace change is visible */
@@ -4063,6 +4042,51 @@ reindex_relation(Oid relid, int flags, ReindexParams *params)
 	return result;
 }
 
+/*
+ * set_rel_tablespace - modify relation tablespace in the pg_class entry.
+ *
+ * 'reloid' is an Oid of relation to be modified.
+ * 'tablespaceOid' is an Oid of new tablespace.
+ *
+ * Catalog modification is done only if tablespaceOid is different from
+ * the currently set.  Returned bool value is indicating whether any changes
+ * were made or not.
+ */
+bool
+set_rel_tablespace(Oid reloid, Oid tablespaceOid)
+{
+	Relation		pg_class;
+	HeapTuple		tuple;
+	Form_pg_class	rd_rel;
+	bool			changed = false;
+	Oid			oldTablespaceOid;
+
+	/* Get a modifiable copy of the relation's pg_class row. */
+	pg_class = table_open(RelationRelationId, RowExclusiveLock);
+
+	tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(reloid));
+	if (!HeapTupleIsValid(tuple))
+		elog(ERROR, "cache lookup failed for relation %u", reloid);
+	rd_rel = (Form_pg_class) GETSTRUCT(tuple);
+
+	/* No work if no change in tablespace. */
+	oldTablespaceOid = rd_rel->reltablespace;
+	if (tablespaceOid != oldTablespaceOid ||
+		(tablespaceOid == MyDatabaseTableSpace && OidIsValid(oldTablespaceOid)))
+	{
+		/* Update the pg_class row. */
+		rd_rel->reltablespace = (tablespaceOid == MyDatabaseTableSpace) ?
+			InvalidOid : tablespaceOid;
+		CatalogTupleUpdate(pg_class, &tuple->t_self, tuple);
+
+		changed = true;
+	}
+
+	heap_freetuple(tuple);
+	table_close(pg_class, RowExclusiveLock);
+
+	return changed;
+}
 
 /* ----------------------------------------------------------------
  *		System index reindexing support
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 4dd54079a2..efcfc2b844 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -2942,41 +2942,6 @@ reindex_error_callback(void *arg)
 				   errinfo->relnamespace, errinfo->relname);
 }
 
-/*
- * This is mostly duplicating ATExecSetTableSpaceNoStorage,
- * which should maybe be factored out to a library function.
- */
-static void
-set_rel_tablespace(Oid reloid, Oid tablespaceOid)
-{
-	Relation		pg_class;
-	HeapTuple		tuple;
-	Form_pg_class	rd_rel;
-	Oid			oldTablespaceOid;
-
-	/* Get a modifiable copy of the relation's pg_class row */
-	pg_class = table_open(RelationRelationId, RowExclusiveLock);
-
-	tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(reloid));
-	if (!HeapTupleIsValid(tuple))
-		elog(ERROR, "cache lookup failed for relation %u", reloid);
-	rd_rel = (Form_pg_class) GETSTRUCT(tuple);
-
-	/* No work if no change in tablespace. */
-	oldTablespaceOid = rd_rel->reltablespace;
-	if (tablespaceOid != oldTablespaceOid ||
-		(tablespaceOid == MyDatabaseTableSpace && OidIsValid(oldTablespaceOid)))
-	{
-		/* Update the pg_class row */
-		rd_rel->reltablespace = (tablespaceOid == MyDatabaseTableSpace) ?
-			InvalidOid : tablespaceOid;
-		CatalogTupleUpdate(pg_class, &tuple->t_self, tuple);
-	}
-
-	heap_freetuple(tuple);
-	table_close(pg_class, RowExclusiveLock);
-}
-
 /*
  * ReindexPartitions
  *
diff --git a/src/include/catalog/index.h b/src/include/catalog/index.h
index 56e403ac61..30cfd1877f 100644
--- a/src/include/catalog/index.h
+++ b/src/include/catalog/index.h
@@ -153,6 +153,8 @@ extern Oid	IndexGetRelation(Oid indexId, bool missing_ok);
 extern void reindex_index(Oid indexId, bool skip_constraint_checks,
 						  char relpersistence, ReindexParams *params);
 
+extern bool set_rel_tablespace(Oid reloid, Oid tablespaceOid);
+
 /* Flag bits for reindex_relation(): */
 #define REINDEX_REL_PROCESS_TOAST			0x01
 #define REINDEX_REL_SUPPRESS_INDEX_USE		0x02
-- 
2.17.0

