]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Remove PlannerInfo's join_search_private method.
authorRobert Haas <rhaas@postgresql.org>
Wed, 20 Aug 2025 19:10:52 +0000 (15:10 -0400)
committerRobert Haas <rhaas@postgresql.org>
Tue, 7 Oct 2025 16:43:45 +0000 (12:43 -0400)
Instead, use the new mechanism that allows planner extensions to store
private state inside a PlannerInfo, treating GEQO as an in-core planner
extension.  This is a useful test of the new facility, and also buys
back a few bytes of storage.

To make this work, we must remove innerrel_is_unique_ext's hack of
testing whether join_search_private is set as a proxy for whether
the join search might be retried. Add a flag that extensions can
use to explicitly signal their intentions instead.

Reviewed-by: Andrei Lepikhov <lepihov@gmail.com>
Reviewed-by: Melanie Plageman <melanieplageman@gmail.com>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: http://postgr.es/m/CA+TgmoYWKHU2hKr62Toyzh-kTDEnMDeLw7gkOOnjL-TnOUq0kQ@mail.gmail.com

src/backend/optimizer/geqo/geqo_eval.c
src/backend/optimizer/geqo/geqo_main.c
src/backend/optimizer/geqo/geqo_random.c
src/backend/optimizer/plan/analyzejoins.c
src/backend/optimizer/plan/planner.c
src/backend/optimizer/prep/prepjointree.c
src/include/nodes/pathnodes.h
src/include/optimizer/geqo.h

index f07d1dc8ac69b4d4e243c975b7ba4505e1131ab2..7fcb1aa70d1c35261df002bda78a10b385f227aa 100644 (file)
@@ -162,7 +162,7 @@ geqo_eval(PlannerInfo *root, Gene *tour, int num_gene)
 RelOptInfo *
 gimme_tree(PlannerInfo *root, Gene *tour, int num_gene)
 {
-       GeqoPrivateData *private = (GeqoPrivateData *) root->join_search_private;
+       GeqoPrivateData *private = GetGeqoPrivateData(root);
        List       *clumps;
        int                     rel_count;
 
index 38402ce58db2561e56519e4f276b9e7e2ac65b85..0064556087a3fe57feacfade62581b3c3101d0d6 100644 (file)
@@ -47,6 +47,8 @@ int                   Geqo_generations;
 double         Geqo_selection_bias;
 double         Geqo_seed;
 
+/* GEQO is treated as an in-core planner extension */
+int                    Geqo_planner_extension_id = -1;
 
 static int     gimme_pool_size(int nr_rel);
 static int     gimme_number_generations(int pool_size);
@@ -98,10 +100,16 @@ geqo(PlannerInfo *root, int number_of_rels, List *initial_rels)
        int                     mutations = 0;
 #endif
 
+       if (Geqo_planner_extension_id < 0)
+               Geqo_planner_extension_id = GetPlannerExtensionId("geqo");
+
 /* set up private information */
-       root->join_search_private = &private;
+       SetPlannerInfoExtensionState(root, Geqo_planner_extension_id, &private);
        private.initial_rels = initial_rels;
 
+/* inform core planner that we may replan */
+       root->assumeReplanning = true;
+
 /* initialize private number generator */
        geqo_set_seed(root, Geqo_seed);
 
@@ -304,7 +312,7 @@ geqo(PlannerInfo *root, int number_of_rels, List *initial_rels)
        free_pool(root, pool);
 
        /* ... clear root pointer to our private storage */
-       root->join_search_private = NULL;
+       SetPlannerInfoExtensionState(root, Geqo_planner_extension_id, NULL);
 
        return best_rel;
 }
index 6c7a411f69f44c6b59a1ddf1165463cb9964f03d..46d28baa2e62bdc96a280e5016e8dcff10caebc7 100644 (file)
 
 #include "optimizer/geqo_random.h"
 
-
 void
 geqo_set_seed(PlannerInfo *root, double seed)
 {
-       GeqoPrivateData *private = (GeqoPrivateData *) root->join_search_private;
+       GeqoPrivateData *private = GetGeqoPrivateData(root);
 
        pg_prng_fseed(&private->random_state, seed);
 }
@@ -27,7 +26,7 @@ geqo_set_seed(PlannerInfo *root, double seed)
 double
 geqo_rand(PlannerInfo *root)
 {
-       GeqoPrivateData *private = (GeqoPrivateData *) root->join_search_private;
+       GeqoPrivateData *private = GetGeqoPrivateData(root);
 
        return pg_prng_double(&private->random_state);
 }
@@ -35,7 +34,7 @@ geqo_rand(PlannerInfo *root)
 int
 geqo_randint(PlannerInfo *root, int upper, int lower)
 {
-       GeqoPrivateData *private = (GeqoPrivateData *) root->join_search_private;
+       GeqoPrivateData *private = GetGeqoPrivateData(root);
 
        /*
         * In current usage, "lower" is never negative so we can just use
index 2a3dea88a94fb2ba0038a25a7996e6ff8e7d6fbd..6a3c030e8efb1d2468c4ce74fe2e16ead08a52fa 100644 (file)
@@ -1425,17 +1425,14 @@ innerrel_is_unique_ext(PlannerInfo *root,
                 *
                 * However, in normal planning mode, caching this knowledge is totally
                 * pointless; it won't be queried again, because we build up joinrels
-                * from smaller to larger.  It is useful in GEQO mode, where the
-                * knowledge can be carried across successive planning attempts; and
-                * it's likely to be useful when using join-search plugins, too. Hence
-                * cache when join_search_private is non-NULL.  (Yeah, that's a hack,
-                * but it seems reasonable.)
+                * from smaller to larger.  It's only useful when using GEQO or
+                * another planner extension that attempts planning multiple times.
                 *
                 * Also, allow callers to override that heuristic and force caching;
                 * that's useful for reduce_unique_semijoins, which calls here before
                 * the normal join search starts.
                 */
-               if (force_cache || root->join_search_private)
+               if (force_cache || root->assumeReplanning)
                {
                        old_context = MemoryContextSwitchTo(root->planner_cxt);
                        innerrel->non_unique_for_rels =
index 3b130e724f722f720475ab743d456c82c0df56a5..0c9397a36c31bda96212299df847eff74c52635e 100644 (file)
@@ -706,6 +706,7 @@ subquery_planner(PlannerGlobal *glob, Query *parse, char *plan_name,
        root->hasAlternativeSubPlans = false;
        root->placeholdersFrozen = false;
        root->hasRecursion = hasRecursion;
+       root->assumeReplanning = false;
        if (hasRecursion)
                root->wt_param_id = assign_special_exec_param(root);
        else
index 563be151a4dd05e97953e9f9f9d87875d880eeca..481d8011791bd51fbc0020bbc1dbc05328a4ffc5 100644 (file)
@@ -1384,6 +1384,7 @@ pull_up_simple_subquery(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte,
        subroot->qual_security_level = 0;
        subroot->placeholdersFrozen = false;
        subroot->hasRecursion = false;
+       subroot->assumeReplanning = false;
        subroot->wt_param_id = -1;
        subroot->non_recursive_path = NULL;
        /* We don't currently need a top JoinDomain for the subroot */
index 554d7c3ef67f018a7a91b086255f6a1c02414c64..4e3230ba23461bc011dfa62d30aa568331394f38 100644 (file)
@@ -536,6 +536,8 @@ struct PlannerInfo
        bool            placeholdersFrozen;
        /* true if planning a recursive WITH item */
        bool            hasRecursion;
+       /* true if a planner extension may replan this subquery */
+       bool            assumeReplanning;
 
        /*
         * The rangetable index for the RTE_GROUP RTE, or 0 if there is no
@@ -582,9 +584,6 @@ struct PlannerInfo
        bool       *isAltSubplan pg_node_attr(read_write_ignore);
        bool       *isUsedSubplan pg_node_attr(read_write_ignore);
 
-       /* optional private data for join_search_hook, e.g., GEQO */
-       void       *join_search_private pg_node_attr(read_write_ignore);
-
        /* Does this query modify any partition key columns? */
        bool            partColsUpdated;
 
index 9f8e0f337aad49b1c8f81a4d768c02f91a0c37f3..b3017dd8ec4770e06d0d64552cd68104ad6ea7c9 100644 (file)
@@ -24,6 +24,7 @@
 
 #include "common/pg_prng.h"
 #include "nodes/pathnodes.h"
+#include "optimizer/extendplan.h"
 #include "optimizer/geqo_gene.h"
 
 
@@ -62,6 +63,8 @@ extern PGDLLIMPORT int Geqo_generations;      /* 1 .. inf, or 0 to use default */
 
 extern PGDLLIMPORT double Geqo_selection_bias;
 
+extern PGDLLIMPORT int Geqo_planner_extension_id;
+
 #define DEFAULT_GEQO_SELECTION_BIAS 2.0
 #define MIN_GEQO_SELECTION_BIAS 1.5
 #define MAX_GEQO_SELECTION_BIAS 2.0
@@ -70,7 +73,7 @@ extern PGDLLIMPORT double Geqo_seed;  /* 0 .. 1 */
 
 
 /*
- * Private state for a GEQO run --- accessible via root->join_search_private
+ * Private state for a GEQO run --- accessible via GetGeqoPrivateData
  */
 typedef struct
 {
@@ -78,6 +81,13 @@ typedef struct
        pg_prng_state random_state; /* PRNG state */
 } GeqoPrivateData;
 
+static inline GeqoPrivateData *
+GetGeqoPrivateData(PlannerInfo *root)
+{
+       /* headers must be C++-compliant, so the cast is required here */
+       return (GeqoPrivateData *)
+               GetPlannerInfoExtensionState(root, Geqo_planner_extension_id);
+}
 
 /* routines in geqo_main.c */
 extern RelOptInfo *geqo(PlannerInfo *root,