From 19f380263cb81a977b3ba8c6fb5fd2b32af4d8ed Mon Sep 17 00:00:00 2001 From: Garrett Thornburg Date: Thu, 20 Jul 2023 20:35:26 -0600 Subject: [PATCH v1] 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 | 35 +++++++++ src/test/regress/sql/event_trigger.sql | 33 ++++++++ 6 files changed, 170 insertions(+), 3 deletions(-) diff --git a/doc/src/sgml/event-trigger.sgml b/doc/src/sgml/event-trigger.sgml index 3b6a5361b3..14d3fac29d 100644 --- a/doc/src/sgml/event-trigger.sgml +++ b/doc/src/sgml/event-trigger.sgml @@ -1013,6 +1013,14 @@ - + + REINDEX + - + X + - + - + + REVOKE X 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..986787bf53 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -554,6 +554,41 @@ 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 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); +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(); +REINDEX INDEX reindex_test.reindex_test1_idx1; +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_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_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_end_command -- REINDEX: CREATE INDEX reindex_test2_idx1 ON reindex_test.reindex_tester2 USING btree (a) +DROP EVENT TRIGGER end_reindex_command; +DROP SCHEMA reindex_test CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table reindex_test.reindex_tester1 +drop cascades to table reindex_test.reindex_tester2 +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..53d0aff398 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -418,6 +418,39 @@ drop table rewriteme; drop event trigger no_rewrite_allowed; drop function test_evtrig_no_rewrite(); +-- test Reindex Event Trigger +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); + +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(); + +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; + +DROP EVENT TRIGGER end_reindex_command; +DROP SCHEMA reindex_test CASCADE; +DROP FUNCTION reindex_start_command; +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