Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * extendplan.c
4 : * Extend core planner objects with additional private state
5 : *
6 : * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
7 : * Portions Copyright (c) 1994-5, Regents of the University of California
8 : *
9 : * The interfaces defined in this file make it possible for loadable
10 : * modules to store their own private state inside of key planner data
11 : * structures -- specifically, the PlannerGlobal, PlannerInfo, and
12 : * RelOptInfo structures. This can make it much easier to write
13 : * reasonably efficient planner extensions; for instance, code that
14 : * uses set_join_pathlist_hook can arrange to compute a key intermediate
15 : * result once per joinrel rather than on every call.
16 : *
17 : * IDENTIFICATION
18 : * src/backend/optimizer/util/extendplan.c
19 : *
20 : *-------------------------------------------------------------------------
21 : */
22 : #include "postgres.h"
23 :
24 : #include "optimizer/extendplan.h"
25 : #include "port/pg_bitutils.h"
26 : #include "utils/memutils.h"
27 :
28 : static const char **PlannerExtensionNameArray = NULL;
29 : static int PlannerExtensionNamesAssigned = 0;
30 : static int PlannerExtensionNamesAllocated = 0;
31 :
32 : /*
33 : * Map the name of a planner extension to an integer ID.
34 : *
35 : * Within the lifetime of a particular backend, the same name will be mapped
36 : * to the same ID every time. IDs are not stable across backends. Use the ID
37 : * that you get from this function to call the remaining functions in this
38 : * file.
39 : */
40 : int
41 6 : GetPlannerExtensionId(const char *extension_name)
42 : {
43 : /* Search for an existing extension by this name; if found, return ID. */
44 6 : for (int i = 0; i < PlannerExtensionNamesAssigned; ++i)
45 0 : if (strcmp(PlannerExtensionNameArray[i], extension_name) == 0)
46 0 : return i;
47 :
48 : /* If there is no array yet, create one. */
49 6 : if (PlannerExtensionNameArray == NULL)
50 : {
51 6 : PlannerExtensionNamesAllocated = 16;
52 6 : PlannerExtensionNameArray = (const char **)
53 6 : MemoryContextAlloc(TopMemoryContext,
54 : PlannerExtensionNamesAllocated
55 : * sizeof(char *));
56 : }
57 :
58 : /* If there's an array but it's currently full, expand it. */
59 6 : if (PlannerExtensionNamesAssigned >= PlannerExtensionNamesAllocated)
60 : {
61 0 : int i = pg_nextpower2_32(PlannerExtensionNamesAssigned + 1);
62 :
63 0 : PlannerExtensionNameArray = (const char **)
64 0 : repalloc(PlannerExtensionNameArray, i * sizeof(char *));
65 0 : PlannerExtensionNamesAllocated = i;
66 : }
67 :
68 : /* Assign and return new ID. */
69 6 : PlannerExtensionNameArray[PlannerExtensionNamesAssigned] = extension_name;
70 6 : return PlannerExtensionNamesAssigned++;
71 : }
72 :
73 : /*
74 : * Store extension-specific state into a PlannerGlobal.
75 : */
76 : void
77 0 : SetPlannerGlobalExtensionState(PlannerGlobal *glob, int extension_id,
78 : void *opaque)
79 : {
80 : Assert(extension_id >= 0);
81 :
82 : /* If there is no array yet, create one. */
83 0 : if (glob->extension_state == NULL)
84 : {
85 : MemoryContext planner_cxt;
86 : Size sz;
87 :
88 0 : planner_cxt = GetMemoryChunkContext(glob);
89 0 : glob->extension_state_allocated =
90 0 : Max(4, pg_nextpower2_32(extension_id + 1));
91 0 : sz = glob->extension_state_allocated * sizeof(void *);
92 0 : glob->extension_state = MemoryContextAllocZero(planner_cxt, sz);
93 : }
94 :
95 : /* If there's an array but it's currently full, expand it. */
96 0 : if (extension_id >= glob->extension_state_allocated)
97 : {
98 : int i;
99 :
100 0 : i = pg_nextpower2_32(extension_id + 1);
101 0 : glob->extension_state = repalloc0_array(glob->extension_state, void *,
102 : glob->extension_state_allocated, i);
103 0 : glob->extension_state_allocated = i;
104 : }
105 :
106 0 : glob->extension_state[extension_id] = opaque;
107 0 : }
108 :
109 : /*
110 : * Store extension-specific state into a PlannerInfo.
111 : */
112 : void
113 42 : SetPlannerInfoExtensionState(PlannerInfo *root, int extension_id,
114 : void *opaque)
115 : {
116 : Assert(extension_id >= 0);
117 :
118 : /* If there is no array yet, create one. */
119 42 : if (root->extension_state == NULL)
120 : {
121 : Size sz;
122 :
123 21 : root->extension_state_allocated =
124 21 : Max(4, pg_nextpower2_32(extension_id + 1));
125 21 : sz = root->extension_state_allocated * sizeof(void *);
126 21 : root->extension_state = MemoryContextAllocZero(root->planner_cxt, sz);
127 : }
128 :
129 : /* If there's an array but it's currently full, expand it. */
130 42 : if (extension_id >= root->extension_state_allocated)
131 : {
132 : int i;
133 :
134 0 : i = pg_nextpower2_32(extension_id + 1);
135 0 : root->extension_state = repalloc0_array(root->extension_state, void *,
136 : root->extension_state_allocated, i);
137 0 : root->extension_state_allocated = i;
138 : }
139 :
140 42 : root->extension_state[extension_id] = opaque;
141 42 : }
142 :
143 : /*
144 : * Store extension-specific state into a RelOptInfo.
145 : */
146 : void
147 0 : SetRelOptInfoExtensionState(RelOptInfo *rel, int extension_id,
148 : void *opaque)
149 : {
150 : Assert(extension_id >= 0);
151 :
152 : /* If there is no array yet, create one. */
153 0 : if (rel->extension_state == NULL)
154 : {
155 : MemoryContext planner_cxt;
156 : Size sz;
157 :
158 0 : planner_cxt = GetMemoryChunkContext(rel);
159 0 : rel->extension_state_allocated =
160 0 : Max(4, pg_nextpower2_32(extension_id + 1));
161 0 : sz = rel->extension_state_allocated * sizeof(void *);
162 0 : rel->extension_state = MemoryContextAllocZero(planner_cxt, sz);
163 : }
164 :
165 : /* If there's an array but it's currently full, expand it. */
166 0 : if (extension_id >= rel->extension_state_allocated)
167 : {
168 : int i;
169 :
170 0 : i = pg_nextpower2_32(extension_id + 1);
171 0 : rel->extension_state = repalloc0_array(rel->extension_state, void *,
172 : rel->extension_state_allocated, i);
173 0 : rel->extension_state_allocated = i;
174 : }
175 :
176 0 : rel->extension_state[extension_id] = opaque;
177 0 : }
|