From ff0488f43db0febc1bcefb5236bbd79db64a506c Mon Sep 17 00:00:00 2001
From: Garrett Thornburg <garrett.thornburg@hey.com>
Date: Thu, 20 Jul 2023 20:35:26 -0600
Subject: [PATCH v2] Add REINDEX tag to event triggers

This turns on the event tag REINDEX. This will now return a record for
each index that was modified during as part of start/end ddl commands.

For concurrent reindex, this will return the OID for the new index. This
includes concurrently reindexing tables and databases. It will only
report the new index records and not the ones destroyed by the
concurrent reindex process.
---
 doc/src/sgml/event-trigger.sgml             |   8 ++
 src/backend/commands/indexcmds.c            |  83 +++++++++++++
 src/backend/tcop/utility.c                  |  12 +-
 src/include/tcop/cmdtaglist.h               |   2 +-
 src/test/regress/expected/event_trigger.out | 126 ++++++++++++++++++++
 src/test/regress/sql/event_trigger.sql      |  99 +++++++++++++++
 6 files changed, 327 insertions(+), 3 deletions(-)

diff --git a/doc/src/sgml/event-trigger.sgml b/doc/src/sgml/event-trigger.sgml
index 3b6a5361b3..aa1b359f35 100644
--- a/doc/src/sgml/event-trigger.sgml
+++ b/doc/src/sgml/event-trigger.sgml
@@ -1013,6 +1013,14 @@
         <entry align="center"><literal>-</literal></entry>
         <entry align="left"></entry>
        </row>
+       <row>
+        <entry align="left"><literal>REINDEX</literal></entry>
+        <entry align="center"><literal>X</literal></entry>
+        <entry align="center"><literal>X</literal></entry>
+        <entry align="center"><literal>-</literal></entry>
+        <entry align="center"><literal>-</literal></entry>
+        <entry align="left"></entry>
+       </row>
        <row>
         <entry align="left"><literal>REVOKE</literal></entry>
         <entry align="center"><literal>X</literal></entry>
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index baf3e6e57a..2dc74225ed 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -94,6 +94,8 @@ static char *ChooseIndexNameAddition(List *colnames);
 static List *ChooseIndexColumnNames(List *indexElems);
 static void ReindexIndex(RangeVar *indexRelation, ReindexParams *params,
 						 bool isTopLevel);
+static void reindex_event_trigger_collect(Oid oid);
+static void reindex_event_trigger_collect_relation(Oid oid);
 static void RangeVarCallbackForReindexIndex(const RangeVar *relation,
 											Oid relId, Oid oldRelId, void *arg);
 static Oid	ReindexTable(RangeVar *relation, ReindexParams *params,
@@ -110,6 +112,8 @@ static bool ReindexRelationConcurrently(Oid relationOid,
 static void update_relispartition(Oid relationId, bool newval);
 static inline void set_indexsafe_procflags(void);
 
+static ReindexStmt *currentReindexStatement = NULL;
+
 /*
  * callback argument type for RangeVarCallbackForReindexIndex()
  */
@@ -2699,6 +2703,12 @@ ExecReindex(ParseState *pstate, ReindexStmt *stmt, bool isTopLevel)
 	bool		verbose = false;
 	char	   *tablespacename = NULL;
 
+	/*
+	 * Make current stmt available for event triggers without directly passing
+	 * the context to every subsequent call.
+	 */
+	currentReindexStatement = stmt;
+
 	/* Parse option list */
 	foreach(lc, stmt->params)
 	{
@@ -2779,6 +2789,12 @@ ExecReindex(ParseState *pstate, ReindexStmt *stmt, bool isTopLevel)
 				 (int) stmt->kind);
 			break;
 	}
+
+	/*
+	 * Clear the reindex stmt global reference now that triggers should have
+	 * completed
+	 */
+	currentReindexStatement = NULL;
 }
 
 /*
@@ -2830,6 +2846,8 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
 
 		newparams.options |= REINDEXOPT_REPORT_PROGRESS;
 		reindex_index(indOid, false, persistence, &newparams);
+		/* Add the index to event trigger */
+		reindex_event_trigger_collect(indOid);
 	}
 }
 
@@ -2953,6 +2971,9 @@ ReindexTable(RangeVar *relation, ReindexParams *params, bool isTopLevel)
 			ereport(NOTICE,
 					(errmsg("table \"%s\" has no indexes to reindex",
 							relation->relname)));
+
+		/* Create even for the indexes being modified */
+		reindex_event_trigger_collect_relation(heapOid);
 	}
 
 	return heapOid;
@@ -3369,6 +3390,8 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
 			newparams.options |=
 				REINDEXOPT_REPORT_PROGRESS | REINDEXOPT_MISSING_OK;
 			reindex_index(relid, false, relpersistence, &newparams);
+			/* Add the index to event trigger */
+			reindex_event_trigger_collect(relid);
 			PopActiveSnapshot();
 			/* reindex_index() does the verbose output */
 		}
@@ -3390,6 +3413,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
 								get_namespace_name(get_rel_namespace(relid)),
 								get_rel_name(relid))));
 
+			/* Create even for the indexes being modified */
+			reindex_event_trigger_collect_relation(relid);
+
 			PopActiveSnapshot();
 		}
 
@@ -3837,6 +3863,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
 
 		newIndexIds = lappend(newIndexIds, newidx);
 
+		/* Add the index to event trigger */
+		reindex_event_trigger_collect(newIndexId);
+
 		/*
 		 * Save lockrelid to protect each relation from drop then close
 		 * relations. The lockrelid on parent relation is not taken here to
@@ -4441,3 +4470,57 @@ set_indexsafe_procflags(void)
 	ProcGlobal->statusFlags[MyProc->pgxactoff] = MyProc->statusFlags;
 	LWLockRelease(ProcArrayLock);
 }
+
+static void
+reindex_event_trigger_collect(Oid oid)
+{
+	ObjectAddress address;
+
+	if (currentReindexStatement == NULL)
+		return;
+
+	address.classId = RelationRelationId;
+	address.objectId = oid;
+	address.objectSubId = 0;
+
+	EventTriggerCollectSimpleCommand(address,
+									 InvalidObjectAddress, (Node *) currentReindexStatement);
+}
+
+static void
+reindex_event_trigger_collect_relation(Oid relid)
+{
+	Relation	rel;
+	List	   *indexIds = NULL;
+	ListCell   *indexId = NULL;
+
+	/*
+	 * Open and lock the relation.  ShareLock is sufficient since we only need
+	 * to prevent schema and data changes in it.  The lock level used here
+	 * should match catalog's reindex_relation().
+	 */
+	rel = try_table_open(relid, ShareLock);
+
+	/* if relation is gone, leave */
+	if (!rel)
+		return;
+
+	/*
+	 * Get the list of index OIDs for this relation.  (We trust to the
+	 * relcache to get this with a sequential scan if ignoring system
+	 * indexes.)
+	 */
+	indexIds = RelationGetIndexList(rel);
+
+	/*
+	 * Get the list of index OIDs for this relation.
+	 */
+	foreach(indexId, indexIds)
+	{
+		Oid			indexOid = lfirst_oid(indexId);
+
+		reindex_event_trigger_collect(indexOid);
+	}
+
+	table_close(rel, ShareLock);
+}
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index e3ccf6c7f7..a269b5b6dc 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -961,7 +961,9 @@ standard_ProcessUtility(PlannedStmt *pstmt,
 			break;
 
 		case T_ReindexStmt:
-			ExecReindex(pstate, (ReindexStmt *) parsetree, isTopLevel);
+			ProcessUtilitySlow(pstate, pstmt, queryString,
+							   context, params, queryEnv,
+							   dest, qc);
 			break;
 
 			/*
@@ -1574,6 +1576,12 @@ ProcessUtilitySlow(ParseState *pstate,
 				}
 				break;
 
+			case T_ReindexStmt:
+				ExecReindex(pstate, (ReindexStmt *) parsetree, isTopLevel);
+				/* no commands stashed for REINDEX */
+				commandCollected = true;
+				break;
+
 			case T_CreateExtensionStmt:
 				address = CreateExtension(pstate, (CreateExtensionStmt *) parsetree);
 				break;
@@ -3620,7 +3628,7 @@ GetCommandLogLevel(Node *parsetree)
 			break;
 
 		case T_ReindexStmt:
-			lev = LOGSTMT_ALL;	/* should this be DDL? */
+			lev = LOGSTMT_DDL;
 			break;
 
 		case T_CreateConversionStmt:
diff --git a/src/include/tcop/cmdtaglist.h b/src/include/tcop/cmdtaglist.h
index e738ac1c09..d0e0b18609 100644
--- a/src/include/tcop/cmdtaglist.h
+++ b/src/include/tcop/cmdtaglist.h
@@ -193,7 +193,7 @@ PG_CMDTAG(CMDTAG_PREPARE, "PREPARE", false, false, false)
 PG_CMDTAG(CMDTAG_PREPARE_TRANSACTION, "PREPARE TRANSACTION", false, false, false)
 PG_CMDTAG(CMDTAG_REASSIGN_OWNED, "REASSIGN OWNED", false, false, false)
 PG_CMDTAG(CMDTAG_REFRESH_MATERIALIZED_VIEW, "REFRESH MATERIALIZED VIEW", true, false, false)
-PG_CMDTAG(CMDTAG_REINDEX, "REINDEX", false, false, false)
+PG_CMDTAG(CMDTAG_REINDEX, "REINDEX", true, false, false)
 PG_CMDTAG(CMDTAG_RELEASE, "RELEASE", false, false, false)
 PG_CMDTAG(CMDTAG_RESET, "RESET", false, false, false)
 PG_CMDTAG(CMDTAG_REVOKE, "REVOKE", true, false, false)
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 5a10958df5..f9bad789c6 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -554,6 +554,132 @@ ERROR:  cannot alter type "rewritetype" because column "rewritemetoo3.a" uses it
 drop table rewriteme;
 drop event trigger no_rewrite_allowed;
 drop function test_evtrig_no_rewrite();
+-- test Reindex Event Trigger
+CREATE OR REPLACE FUNCTION reindex_start_command()
+RETURNS event_trigger AS $$
+BEGIN
+  RAISE NOTICE 'ddl_start_command -- REINDEX: % %', tg_event, tg_tag;
+END;
+$$ LANGUAGE plpgsql;
+CREATE EVENT TRIGGER start_reindex_command ON ddl_command_start
+    WHEN TAG IN ('REINDEX') EXECUTE PROCEDURE reindex_start_command();
+CREATE OR REPLACE FUNCTION reindex_end_command()
+RETURNS event_trigger AS $$
+DECLARE
+  obj record;
+BEGIN
+  FOR obj IN SELECT * FROM pg_event_trigger_ddl_commands()
+    LOOP
+      RAISE NOTICE 'ddl_end_command -- REINDEX: %', pg_get_indexdef(obj.objid);
+    END LOOP;
+END;
+$$ LANGUAGE plpgsql;
+CREATE EVENT TRIGGER end_reindex_command ON ddl_command_end
+    WHEN TAG IN ('REINDEX') EXECUTE PROCEDURE reindex_end_command();
+-- test REINDEX event for a standard table
+DROP SCHEMA IF EXISTS reindex_test CASCADE;
+NOTICE:  schema "reindex_test" does not exist, skipping
+CREATE SCHEMA reindex_test;
+CREATE TABLE reindex_test.reindex_tester1 (a int);
+CREATE INDEX reindex_test1_idx1 ON reindex_test.reindex_tester1 (a);
+CREATE INDEX reindex_test1_idx2 ON reindex_test.reindex_tester1 (a);
+CREATE TABLE reindex_test.reindex_tester2 (a int);
+CREATE INDEX reindex_test2_idx1 ON reindex_test.reindex_tester2 (a);
+REINDEX INDEX reindex_test.reindex_test1_idx1;
+NOTICE:  ddl_start_command -- REINDEX: ddl_command_start REINDEX
+NOTICE:  ddl_end_command -- REINDEX: CREATE INDEX reindex_test1_idx1 ON reindex_test.reindex_tester1 USING btree (a)
+REINDEX TABLE reindex_test.reindex_tester1;
+NOTICE:  ddl_start_command -- REINDEX: ddl_command_start REINDEX
+NOTICE:  ddl_end_command -- REINDEX: CREATE INDEX reindex_test1_idx1 ON reindex_test.reindex_tester1 USING btree (a)
+NOTICE:  ddl_end_command -- REINDEX: CREATE INDEX reindex_test1_idx2 ON reindex_test.reindex_tester1 USING btree (a)
+REINDEX INDEX CONCURRENTLY reindex_test.reindex_test2_idx1;
+NOTICE:  ddl_start_command -- REINDEX: ddl_command_start REINDEX
+NOTICE:  ddl_end_command -- REINDEX: CREATE INDEX reindex_test2_idx1 ON reindex_test.reindex_tester2 USING btree (a)
+REINDEX TABLE CONCURRENTLY reindex_test.reindex_tester2;
+NOTICE:  ddl_start_command -- REINDEX: ddl_command_start REINDEX
+NOTICE:  ddl_end_command -- REINDEX: CREATE INDEX reindex_test2_idx1 ON reindex_test.reindex_tester2 USING btree (a)
+-- test REINDEX event for a partitioned table
+CREATE TABLE reindex_test.ptif_test (a int, b int) PARTITION BY range (a);
+CREATE TABLE reindex_test.ptif_test0 PARTITION OF reindex_test.ptif_test
+  FOR VALUES FROM (minvalue) TO (0) PARTITION BY list (b);
+CREATE TABLE reindex_test.ptif_test01 PARTITION OF reindex_test.ptif_test0 FOR VALUES IN (1);
+CREATE TABLE reindex_test.ptif_test1 PARTITION OF reindex_test.ptif_test
+  FOR VALUES FROM (0) TO (100) PARTITION BY list (b);
+CREATE TABLE reindex_test.ptif_test11 PARTITION OF reindex_test.ptif_test1 FOR VALUES IN (1);
+CREATE TABLE reindex_test.ptif_test2 PARTITION OF reindex_test.ptif_test
+  FOR VALUES FROM (100) TO (200);
+-- This partitioned table should remain with no partitions.
+CREATE TABLE reindex_test.ptif_test3 PARTITION OF reindex_test.ptif_test
+  FOR VALUES FROM (200) TO (maxvalue) PARTITION BY list (b);
+CREATE INDEX ptif_test_index ON ONLY reindex_test.ptif_test (a);
+CREATE INDEX ptif_test0_index ON ONLY reindex_test.ptif_test0 (a);
+ALTER INDEX reindex_test.ptif_test_index ATTACH PARTITION reindex_test.ptif_test0_index;
+CREATE INDEX ptif_test01_index ON reindex_test.ptif_test01 (a);
+ALTER INDEX reindex_test.ptif_test0_index ATTACH PARTITION reindex_test.ptif_test01_index;
+CREATE INDEX ptif_test1_index ON ONLY reindex_test.ptif_test1 (a);
+ALTER INDEX reindex_test.ptif_test_index ATTACH PARTITION reindex_test.ptif_test1_index;
+CREATE INDEX ptif_test11_index ON reindex_test.ptif_test11 (a);
+ALTER INDEX reindex_test.ptif_test1_index ATTACH PARTITION reindex_test.ptif_test11_index;
+CREATE INDEX ptif_test2_index ON reindex_test.ptif_test2 (a);
+ALTER INDEX reindex_test.ptif_test_index ATTACH PARTITION reindex_test.ptif_test2_index;
+CREATE INDEX ptif_test3_index ON reindex_test.ptif_test3 (a);
+ALTER INDEX reindex_test.ptif_test_index ATTACH PARTITION reindex_test.ptif_test3_index;
+-- reindex at the top level table to recursively reindex each partition
+REINDEX INDEX CONCURRENTLY reindex_test.ptif_test_index;
+NOTICE:  ddl_start_command -- REINDEX: ddl_command_start REINDEX
+NOTICE:  ddl_end_command -- REINDEX: CREATE INDEX ptif_test2_index ON reindex_test.ptif_test2 USING btree (a)
+NOTICE:  ddl_end_command -- REINDEX: CREATE INDEX ptif_test01_index ON reindex_test.ptif_test01 USING btree (a)
+NOTICE:  ddl_end_command -- REINDEX: CREATE INDEX ptif_test11_index ON reindex_test.ptif_test11 USING btree (a)
+-- ptif_test0 is partitioned table so it will index partition: ptif_test01_index
+-- event trigger will log ptif_test01_index
+REINDEX INDEX CONCURRENTLY reindex_test.ptif_test0_index;
+NOTICE:  ddl_start_command -- REINDEX: ddl_command_start REINDEX
+NOTICE:  ddl_end_command -- REINDEX: CREATE INDEX ptif_test01_index ON reindex_test.ptif_test01 USING btree (a)
+-- ptif_test1_index is partitioned index so it will index partition: ptif_test11_index
+-- event trigger will effect on partion index:ptif_test11_index
+REINDEX INDEX CONCURRENTLY reindex_test.ptif_test1_index;
+NOTICE:  ddl_start_command -- REINDEX: ddl_command_start REINDEX
+NOTICE:  ddl_end_command -- REINDEX: CREATE INDEX ptif_test11_index ON reindex_test.ptif_test11 USING btree (a)
+-- ptif_test2 is a partition so event trigger will log ptif_test2_index
+REINDEX INDEX CONCURRENTLY reindex_test.ptif_test2_index;
+NOTICE:  ddl_start_command -- REINDEX: ddl_command_start REINDEX
+NOTICE:  ddl_end_command -- REINDEX: CREATE INDEX ptif_test2_index ON reindex_test.ptif_test2 USING btree (a)
+-- no partitions: event trigger won't do anything
+REINDEX INDEX CONCURRENTLY reindex_test.ptif_test3_index;
+NOTICE:  ddl_start_command -- REINDEX: ddl_command_start REINDEX
+-- reindex at the top level table to recursively reindex each partition
+REINDEX TABLE reindex_test.ptif_test;
+NOTICE:  ddl_start_command -- REINDEX: ddl_command_start REINDEX
+NOTICE:  ddl_end_command -- REINDEX: CREATE INDEX ptif_test2_index ON reindex_test.ptif_test2 USING btree (a)
+NOTICE:  ddl_end_command -- REINDEX: CREATE INDEX ptif_test01_index ON reindex_test.ptif_test01 USING btree (a)
+NOTICE:  ddl_end_command -- REINDEX: CREATE INDEX ptif_test11_index ON reindex_test.ptif_test11 USING btree (a)
+-- will direct to ptif_test01
+REINDEX TABLE reindex_test.ptif_test0;
+NOTICE:  ddl_start_command -- REINDEX: ddl_command_start REINDEX
+NOTICE:  ddl_end_command -- REINDEX: CREATE INDEX ptif_test01_index ON reindex_test.ptif_test01 USING btree (a)
+-- will index its associtaed index
+REINDEX TABLE reindex_test.ptif_test01;
+NOTICE:  ddl_start_command -- REINDEX: ddl_command_start REINDEX
+NOTICE:  ddl_end_command -- REINDEX: CREATE INDEX ptif_test01_index ON reindex_test.ptif_test01 USING btree (a)
+-- will index its associtaed index
+REINDEX TABLE reindex_test.ptif_test11;
+NOTICE:  ddl_start_command -- REINDEX: ddl_command_start REINDEX
+NOTICE:  ddl_end_command -- REINDEX: CREATE INDEX ptif_test11_index ON reindex_test.ptif_test11 USING btree (a)
+-- will index its associtaed index
+REINDEX TABLE reindex_test.ptif_test2;
+NOTICE:  ddl_start_command -- REINDEX: ddl_command_start REINDEX
+NOTICE:  ddl_end_command -- REINDEX: CREATE INDEX ptif_test2_index ON reindex_test.ptif_test2 USING btree (a)
+-- no partion, index won't do anything
+REINDEX TABLE reindex_test.ptif_test3;
+NOTICE:  ddl_start_command -- REINDEX: ddl_command_start REINDEX
+DROP EVENT TRIGGER start_reindex_command;
+DROP EVENT TRIGGER end_reindex_command;
+DROP SCHEMA reindex_test CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to table reindex_test.reindex_tester1
+drop cascades to table reindex_test.reindex_tester2
+drop cascades to table reindex_test.ptif_test
+DROP FUNCTION reindex_end_command;
 -- test Row Security Event Trigger
 RESET SESSION AUTHORIZATION;
 CREATE TABLE event_trigger_test (a integer, b text);
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 1aeaddbe71..d5d51bd9db 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -418,6 +418,105 @@ drop table rewriteme;
 drop event trigger no_rewrite_allowed;
 drop function test_evtrig_no_rewrite();
 
+-- test Reindex Event Trigger
+CREATE OR REPLACE FUNCTION reindex_start_command()
+RETURNS event_trigger AS $$
+BEGIN
+  RAISE NOTICE 'ddl_start_command -- REINDEX: % %', tg_event, tg_tag;
+END;
+$$ LANGUAGE plpgsql;
+
+CREATE EVENT TRIGGER start_reindex_command ON ddl_command_start
+    WHEN TAG IN ('REINDEX') EXECUTE PROCEDURE reindex_start_command();
+
+CREATE OR REPLACE FUNCTION reindex_end_command()
+RETURNS event_trigger AS $$
+DECLARE
+  obj record;
+BEGIN
+  FOR obj IN SELECT * FROM pg_event_trigger_ddl_commands()
+    LOOP
+      RAISE NOTICE 'ddl_end_command -- REINDEX: %', pg_get_indexdef(obj.objid);
+    END LOOP;
+END;
+$$ LANGUAGE plpgsql;
+
+CREATE EVENT TRIGGER end_reindex_command ON ddl_command_end
+    WHEN TAG IN ('REINDEX') EXECUTE PROCEDURE reindex_end_command();
+
+-- test REINDEX event for a standard table
+DROP SCHEMA IF EXISTS reindex_test CASCADE;
+CREATE SCHEMA reindex_test;
+CREATE TABLE reindex_test.reindex_tester1 (a int);
+CREATE INDEX reindex_test1_idx1 ON reindex_test.reindex_tester1 (a);
+CREATE INDEX reindex_test1_idx2 ON reindex_test.reindex_tester1 (a);
+CREATE TABLE reindex_test.reindex_tester2 (a int);
+CREATE INDEX reindex_test2_idx1 ON reindex_test.reindex_tester2 (a);
+
+REINDEX INDEX reindex_test.reindex_test1_idx1;
+REINDEX TABLE reindex_test.reindex_tester1;
+REINDEX INDEX CONCURRENTLY reindex_test.reindex_test2_idx1;
+REINDEX TABLE CONCURRENTLY reindex_test.reindex_tester2;
+
+-- test REINDEX event for a partitioned table
+CREATE TABLE reindex_test.ptif_test (a int, b int) PARTITION BY range (a);
+CREATE TABLE reindex_test.ptif_test0 PARTITION OF reindex_test.ptif_test
+  FOR VALUES FROM (minvalue) TO (0) PARTITION BY list (b);
+CREATE TABLE reindex_test.ptif_test01 PARTITION OF reindex_test.ptif_test0 FOR VALUES IN (1);
+CREATE TABLE reindex_test.ptif_test1 PARTITION OF reindex_test.ptif_test
+  FOR VALUES FROM (0) TO (100) PARTITION BY list (b);
+CREATE TABLE reindex_test.ptif_test11 PARTITION OF reindex_test.ptif_test1 FOR VALUES IN (1);
+CREATE TABLE reindex_test.ptif_test2 PARTITION OF reindex_test.ptif_test
+  FOR VALUES FROM (100) TO (200);
+-- This partitioned table should remain with no partitions.
+CREATE TABLE reindex_test.ptif_test3 PARTITION OF reindex_test.ptif_test
+  FOR VALUES FROM (200) TO (maxvalue) PARTITION BY list (b);
+
+CREATE INDEX ptif_test_index ON ONLY reindex_test.ptif_test (a);
+CREATE INDEX ptif_test0_index ON ONLY reindex_test.ptif_test0 (a);
+ALTER INDEX reindex_test.ptif_test_index ATTACH PARTITION reindex_test.ptif_test0_index;
+CREATE INDEX ptif_test01_index ON reindex_test.ptif_test01 (a);
+ALTER INDEX reindex_test.ptif_test0_index ATTACH PARTITION reindex_test.ptif_test01_index;
+CREATE INDEX ptif_test1_index ON ONLY reindex_test.ptif_test1 (a);
+ALTER INDEX reindex_test.ptif_test_index ATTACH PARTITION reindex_test.ptif_test1_index;
+CREATE INDEX ptif_test11_index ON reindex_test.ptif_test11 (a);
+ALTER INDEX reindex_test.ptif_test1_index ATTACH PARTITION reindex_test.ptif_test11_index;
+CREATE INDEX ptif_test2_index ON reindex_test.ptif_test2 (a);
+ALTER INDEX reindex_test.ptif_test_index ATTACH PARTITION reindex_test.ptif_test2_index;
+CREATE INDEX ptif_test3_index ON reindex_test.ptif_test3 (a);
+ALTER INDEX reindex_test.ptif_test_index ATTACH PARTITION reindex_test.ptif_test3_index;
+
+-- reindex at the top level table to recursively reindex each partition
+REINDEX INDEX CONCURRENTLY reindex_test.ptif_test_index;
+-- ptif_test0 is partitioned table so it will index partition: ptif_test01_index
+-- event trigger will log ptif_test01_index
+REINDEX INDEX CONCURRENTLY reindex_test.ptif_test0_index;
+-- ptif_test1_index is partitioned index so it will index partition: ptif_test11_index
+-- event trigger will effect on partion index:ptif_test11_index
+REINDEX INDEX CONCURRENTLY reindex_test.ptif_test1_index;
+-- ptif_test2 is a partition so event trigger will log ptif_test2_index
+REINDEX INDEX CONCURRENTLY reindex_test.ptif_test2_index;
+-- no partitions: event trigger won't do anything
+REINDEX INDEX CONCURRENTLY reindex_test.ptif_test3_index;
+
+-- reindex at the top level table to recursively reindex each partition
+REINDEX TABLE reindex_test.ptif_test;
+-- will direct to ptif_test01
+REINDEX TABLE reindex_test.ptif_test0;
+-- will index its associtaed index
+REINDEX TABLE reindex_test.ptif_test01;
+-- will index its associtaed index
+REINDEX TABLE reindex_test.ptif_test11;
+-- will index its associtaed index
+REINDEX TABLE reindex_test.ptif_test2;
+-- no partion, index won't do anything
+REINDEX TABLE reindex_test.ptif_test3;
+
+DROP EVENT TRIGGER start_reindex_command;
+DROP EVENT TRIGGER end_reindex_command;
+DROP SCHEMA reindex_test CASCADE;
+DROP FUNCTION reindex_end_command;
+
 -- test Row Security Event Trigger
 RESET SESSION AUTHORIZATION;
 CREATE TABLE event_trigger_test (a integer, b text);
-- 
2.38.1

