Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * extendplan.c
4 : : * Extend core planner objects with additional private state
5 : : *
6 : : * Portions Copyright (c) 1996-2025, 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
20 rhaas@postgresql.org 41 :GNC 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)
20 rhaas@postgresql.org 45 [ # # ]:UNC 0 : if (strcmp(PlannerExtensionNameArray[i], extension_name) == 0)
46 : 0 : return i;
47 : :
48 : : /* If there is no array yet, create one. */
20 rhaas@postgresql.org 49 [ + - ]:GNC 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 : : {
20 rhaas@postgresql.org 61 :UNC 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. */
20 rhaas@postgresql.org 69 :GNC 6 : PlannerExtensionNameArray[PlannerExtensionNamesAssigned] = extension_name;
70 : 6 : return PlannerExtensionNamesAssigned++;
71 : : }
72 : :
73 : : /*
74 : : * Store extension-specific state into a PlannerGlobal.
75 : : */
76 : : void
20 rhaas@postgresql.org 77 :UNC 0 : SetPlannerGlobalExtensionState(PlannerGlobal *glob, int extension_id,
78 : : void *opaque)
79 : : {
80 [ # # ]: 0 : 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 = (void **)
102 : 0 : repalloc0(glob->extension_state,
103 : 0 : glob->extension_state_allocated * sizeof(void *),
104 : : i * sizeof(void *));
105 : 0 : glob->extension_state_allocated = i;
106 : : }
107 : :
108 : 0 : glob->extension_state[extension_id] = opaque;
109 : 0 : }
110 : :
111 : : /*
112 : : * Store extension-specific state into a PlannerInfo.
113 : : */
114 : : void
20 rhaas@postgresql.org 115 :GNC 42 : SetPlannerInfoExtensionState(PlannerInfo *root, int extension_id,
116 : : void *opaque)
117 : : {
118 [ - + ]: 42 : Assert(extension_id >= 0);
119 : :
120 : : /* If there is no array yet, create one. */
121 [ + + ]: 42 : if (root->extension_state == NULL)
122 : : {
123 : : Size sz;
124 : :
125 : 21 : root->extension_state_allocated =
126 [ - + ]: 21 : Max(4, pg_nextpower2_32(extension_id + 1));
127 : 21 : sz = root->extension_state_allocated * sizeof(void *);
128 : 21 : root->extension_state = MemoryContextAllocZero(root->planner_cxt, sz);
129 : : }
130 : :
131 : : /* If there's an array but it's currently full, expand it. */
132 [ - + ]: 42 : if (extension_id >= root->extension_state_allocated)
133 : : {
134 : : int i;
135 : :
20 rhaas@postgresql.org 136 :UNC 0 : i = pg_nextpower2_32(extension_id + 1);
137 : 0 : root->extension_state = (void **)
138 : 0 : repalloc0(root->extension_state,
139 : 0 : root->extension_state_allocated * sizeof(void *),
140 : : i * sizeof(void *));
141 : 0 : root->extension_state_allocated = i;
142 : : }
143 : :
20 rhaas@postgresql.org 144 :GNC 42 : root->extension_state[extension_id] = opaque;
145 : 42 : }
146 : :
147 : : /*
148 : : * Store extension-specific state into a RelOptInfo.
149 : : */
150 : : void
20 rhaas@postgresql.org 151 :UNC 0 : SetRelOptInfoExtensionState(RelOptInfo *rel, int extension_id,
152 : : void *opaque)
153 : : {
154 [ # # ]: 0 : Assert(extension_id >= 0);
155 : :
156 : : /* If there is no array yet, create one. */
157 [ # # ]: 0 : if (rel->extension_state == NULL)
158 : : {
159 : : MemoryContext planner_cxt;
160 : : Size sz;
161 : :
162 : 0 : planner_cxt = GetMemoryChunkContext(rel);
163 : 0 : rel->extension_state_allocated =
164 [ # # ]: 0 : Max(4, pg_nextpower2_32(extension_id + 1));
165 : 0 : sz = rel->extension_state_allocated * sizeof(void *);
166 : 0 : rel->extension_state = MemoryContextAllocZero(planner_cxt, sz);
167 : : }
168 : :
169 : : /* If there's an array but it's currently full, expand it. */
170 [ # # ]: 0 : if (extension_id >= rel->extension_state_allocated)
171 : : {
172 : : int i;
173 : :
174 : 0 : i = pg_nextpower2_32(extension_id + 1);
175 : 0 : rel->extension_state = (void **)
176 : 0 : repalloc0(rel->extension_state,
177 : 0 : rel->extension_state_allocated * sizeof(void *),
178 : : i * sizeof(void *));
179 : 0 : rel->extension_state_allocated = i;
180 : : }
181 : :
182 : 0 : rel->extension_state[extension_id] = opaque;
183 : 0 : }
|