From 7b32e6ebacb79508eae5b699fc016294b48ee32a Mon Sep 17 00:00:00 2001
From: Robert Haas <rhaas@postgresql.org>
Date: Wed, 24 Sep 2025 11:21:55 -0400
Subject: [PATCH v6 5/7] Add planner_setup_hook and planner_shutdown_hook.

These hooks allow plugins to get control at the earliest point at
which the PlannerGlobal object is fully initialized, and then just
before it gets destroyed. This is useful in combination with the
extendable plan state facilities (see extendplan.h) and perhaps for
other purposes as well.
---
 src/backend/optimizer/plan/planner.c | 14 ++++++++++++++
 src/include/optimizer/planner.h      | 13 +++++++++++++
 2 files changed, 27 insertions(+)

diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index 205d8886a2a..ebcf9ea5851 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -73,6 +73,12 @@ bool		enable_distinct_reordering = true;
 /* Hook for plugins to get control in planner() */
 planner_hook_type planner_hook = NULL;
 
+/* Hook for plugins to get control after PlannerGlobal is initialized */
+planner_setup_hook_type planner_setup_hook = NULL;
+
+/* Hook for plugins to get control before PlannerGlobal is discarded */
+planner_shutdown_hook_type planner_shutdown_hook = NULL;
+
 /* Hook for plugins to get control when grouping_planner() plans upper rels */
 create_upper_paths_hook_type create_upper_paths_hook = NULL;
 
@@ -440,6 +446,10 @@ standard_planner(Query *parse, const char *query_string, int cursorOptions,
 		tuple_fraction = 0.0;
 	}
 
+	/* Allow plugins to take control after we've initialized "glob" */
+	if (planner_setup_hook)
+		(*planner_setup_hook) (glob, parse, query_string, &tuple_fraction, es);
+
 	/* primary planning entry point (may recurse for subqueries) */
 	root = subquery_planner(glob, parse, NULL, false, tuple_fraction, NULL);
 
@@ -618,6 +628,10 @@ standard_planner(Query *parse, const char *query_string, int cursorOptions,
 			result->jitFlags |= PGJIT_DEFORM;
 	}
 
+	/* Allow plugins to take control before we discard "glob" */
+	if (planner_shutdown_hook)
+		(*planner_shutdown_hook) (glob, parse, query_string, result);
+
 	if (glob->partition_directory != NULL)
 		DestroyPartitionDirectory(glob->partition_directory);
 
diff --git a/src/include/optimizer/planner.h b/src/include/optimizer/planner.h
index b31ea2fbbdc..a39389728aa 100644
--- a/src/include/optimizer/planner.h
+++ b/src/include/optimizer/planner.h
@@ -32,6 +32,19 @@ typedef PlannedStmt *(*planner_hook_type) (Query *parse,
 										   ExplainState *es);
 extern PGDLLIMPORT planner_hook_type planner_hook;
 
+/* Hook for plugins to get control after PlannerGlobal is initialized */
+typedef void (*planner_setup_hook_type) (PlannerGlobal *glob, Query *parse,
+										 const char *query_string,
+										 double *tuple_fraction,
+										 ExplainState *es);
+extern PGDLLIMPORT planner_setup_hook_type planner_setup_hook;
+
+/* Hook for plugins to get control before PlannerGlobal is discarded */
+typedef void (*planner_shutdown_hook_type) (PlannerGlobal *glob, Query *parse,
+											const char *query_string,
+											PlannedStmt *pstmt);
+extern PGDLLIMPORT planner_shutdown_hook_type planner_shutdown_hook;
+
 /* Hook for plugins to get control when grouping_planner() plans upper rels */
 typedef void (*create_upper_paths_hook_type) (PlannerInfo *root,
 											  UpperRelationKind stage,
-- 
2.39.5 (Apple Git-154)

