From 196baba104ba6c78b00f90007788bea8bd4ba96f Mon Sep 17 00:00:00 2001
From: Alexander Korotkov <akorotkov@postgresql.org>
Date: Sat, 17 Jun 2023 22:01:01 +0300
Subject: [PATCH 5/8] Notify table AM about index creation

This allows table AM to do some preparation with index build.  In particular,
table AM could update its specific meta-information.  That could be also useful
if table AM overrides index implementations.
---
 src/backend/access/heap/heapam_handler.c |  2 ++
 src/backend/catalog/index.c              |  2 ++
 src/backend/commands/indexcmds.c         | 41 +++++++++++++----------
 src/include/access/tableam.h             | 42 ++++++++++++++++++++++++
 4 files changed, 69 insertions(+), 18 deletions(-)

diff --git a/src/backend/access/heap/heapam_handler.c b/src/backend/access/heap/heapam_handler.c
index c67a9aba389..1ebda05797f 100644
--- a/src/backend/access/heap/heapam_handler.c
+++ b/src/backend/access/heap/heapam_handler.c
@@ -3230,6 +3230,8 @@ static const TableAmRoutine heapam_methods = {
 	.index_build_range_scan = heapam_index_build_range_scan,
 	.index_validate_scan = heapam_index_validate_scan,
 	.relation_analyze = heapam_analyze,
+	.define_index_validate = NULL,
+	.define_index = NULL,
 
 	.free_rd_amcache = NULL,
 	.relation_size = table_block_relation_size,
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index b6a7c60e230..bca97981051 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3840,6 +3840,8 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 
 	/* Close rels, but keep locks */
 	index_close(iRel, NoLock);
+	table_define_index(heapRelation, indexId, true,
+					   skip_constraint_checks, false, NULL);
 	table_close(heapRelation, NoLock);
 
 	if (progress)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index e78598c10e1..2570e7a24a1 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -583,6 +583,7 @@ DefineIndex(Oid tableId,
 	Oid			root_save_userid;
 	int			root_save_sec_context;
 	int			root_save_nestlevel;
+	void	   *arg;
 
 	root_save_nestlevel = NewGUCNestLevel();
 
@@ -629,6 +630,26 @@ DefineIndex(Oid tableId,
 	pgstat_progress_update_param(PROGRESS_CREATEIDX_INDEX_OID,
 								 InvalidOid);
 
+	/*
+	 * Only SELECT ... FOR UPDATE/SHARE are allowed while doing a standard
+	 * index build; but for concurrent builds we allow INSERT/UPDATE/DELETE
+	 * (but not VACUUM).
+	 *
+	 * NB: Caller is responsible for making sure that relationId refers to the
+	 * relation on which the index should be built; except in bootstrap mode,
+	 * this will typically require the caller to have already locked the
+	 * relation.  To avoid lock upgrade hazards, that lock should be at least
+	 * as strong as the one we take here.
+	 *
+	 * NB: If the lock strength here ever changes, code that is run by
+	 * parallel workers under the control of certain particular ambuild
+	 * functions will need to be updated, too.
+	 */
+	lockmode = concurrent ? ShareUpdateExclusiveLock : ShareLock;
+	rel = table_open(tableId, lockmode);
+
+	table_define_index_validate(rel, stmt, skip_build, &arg);
+
 	/*
 	 * count key attributes in index
 	 */
@@ -656,24 +677,6 @@ DefineIndex(Oid tableId,
 				 errmsg("cannot use more than %d columns in an index",
 						INDEX_MAX_KEYS)));
 
-	/*
-	 * Only SELECT ... FOR UPDATE/SHARE are allowed while doing a standard
-	 * index build; but for concurrent builds we allow INSERT/UPDATE/DELETE
-	 * (but not VACUUM).
-	 *
-	 * NB: Caller is responsible for making sure that tableId refers to the
-	 * relation on which the index should be built; except in bootstrap mode,
-	 * this will typically require the caller to have already locked the
-	 * relation.  To avoid lock upgrade hazards, that lock should be at least
-	 * as strong as the one we take here.
-	 *
-	 * NB: If the lock strength here ever changes, code that is run by
-	 * parallel workers under the control of certain particular ambuild
-	 * functions will need to be updated, too.
-	 */
-	lockmode = concurrent ? ShareUpdateExclusiveLock : ShareLock;
-	rel = table_open(tableId, lockmode);
-
 	/*
 	 * Switch to the table owner's userid, so that any index functions are run
 	 * as that user.  Also lock down security-restricted operations.  We
@@ -1218,6 +1221,8 @@ DefineIndex(Oid tableId,
 
 	ObjectAddressSet(address, RelationRelationId, indexRelationId);
 
+	table_define_index(rel, address.objectId, false, false,
+					   skip_build, arg);
 	if (!OidIsValid(indexRelationId))
 	{
 		/*
diff --git a/src/include/access/tableam.h b/src/include/access/tableam.h
index e4fdd0b5ec6..4e9dab67969 100644
--- a/src/include/access/tableam.h
+++ b/src/include/access/tableam.h
@@ -684,6 +684,16 @@ typedef struct TableAmRoutine
 									 BlockNumber *totalpages,
 									 BufferAccessStrategy bstrategy);
 
+	/* See table_define_index_validate() */
+	bool		(*define_index_validate) (Relation rel, IndexStmt *stmt,
+										  bool skip_build, void **arg);
+
+	/* See table_define_index() */
+	bool		(*define_index) (Relation rel, Oid indoid, bool reindex,
+								 bool skip_constraint_checks, bool skip_build,
+								 void *arg);
+
+
 
 	/* ------------------------------------------------------------------------
 	 * Miscellaneous functions.
@@ -1860,6 +1870,38 @@ table_relation_analyze(Relation relation, AcquireSampleRowsFunc *func,
 										   totalpages, bstrategy);
 }
 
+/*
+ * Let table AM validate the index to be created on `rel` with statement
+ * `*stmt`.  `skip_build` indicates that only catalog entries are to be
+ * created without index data.  This method can save some information into
+ * `arg`, and it shoud be passed to table_define_index().
+ */
+static inline bool
+table_define_index_validate(Relation rel, IndexStmt *stmt,
+							bool skip_build, void **arg)
+{
+	if (rel->rd_tableam && rel->rd_tableam->define_index_validate)
+		return rel->rd_tableam->define_index_validate(rel, stmt,
+													  skip_build, arg);
+	else
+		return true;
+}
+
+/*
+ * Notifies table AM about index creation on `rel` with oid `indoid`.
+ */
+static inline bool
+table_define_index(Relation rel, Oid indoid, bool reindex,
+				   bool skip_constraint_checks, bool skip_build, void *arg)
+{
+	if (rel->rd_tableam && rel->rd_tableam->define_index)
+		return rel->rd_tableam->define_index(rel, indoid, reindex,
+											 skip_constraint_checks,
+											 skip_build, arg);
+	else
+		return true;
+}
+
 /* ----------------------------------------------------------------------------
  * Miscellaneous functionality
  * ----------------------------------------------------------------------------
-- 
2.39.3 (Apple Git-145)

