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-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
324 rhaas@postgresql.org 41 :CBC 30 : GetPlannerExtensionId(const char *extension_name)
42 : : {
43 : : /* Search for an existing extension by this name; if found, return ID. */
44 [ + + ]: 32 : for (int i = 0; i < PlannerExtensionNamesAssigned; ++i)
45 [ - + ]: 2 : if (strcmp(PlannerExtensionNameArray[i], extension_name) == 0)
324 rhaas@postgresql.org 46 :UBC 0 : return i;
47 : :
48 : : /* If there is no array yet, create one. */
324 rhaas@postgresql.org 49 [ + + ]:CBC 30 : if (PlannerExtensionNameArray == NULL)
50 : : {
51 : 28 : PlannerExtensionNamesAllocated = 16;
52 : 28 : PlannerExtensionNameArray = (const char **)
53 : 28 : MemoryContextAlloc(TopMemoryContext,
54 : : PlannerExtensionNamesAllocated
55 : : * sizeof(char *));
56 : : }
57 : :
58 : : /* If there's an array but it's currently full, expand it. */
59 [ - + ]: 30 : if (PlannerExtensionNamesAssigned >= PlannerExtensionNamesAllocated)
60 : : {
324 rhaas@postgresql.org 61 :UBC 0 : int i = pg_nextpower2_32(PlannerExtensionNamesAssigned + 1);
62 : :
10 michael@paquier.xyz 63 :UNC 0 : PlannerExtensionNameArray = repalloc_array(PlannerExtensionNameArray, const char *, i);
324 rhaas@postgresql.org 64 :UBC 0 : PlannerExtensionNamesAllocated = i;
65 : : }
66 : :
67 : : /* Assign and return new ID. */
324 rhaas@postgresql.org 68 :CBC 30 : PlannerExtensionNameArray[PlannerExtensionNamesAssigned] = extension_name;
69 : 30 : return PlannerExtensionNamesAssigned++;
70 : : }
71 : :
72 : : /*
73 : : * Store extension-specific state into a PlannerGlobal.
74 : : */
75 : : void
76 : 88489 : SetPlannerGlobalExtensionState(PlannerGlobal *glob, int extension_id,
77 : : void *opaque)
78 : : {
79 [ - + ]: 88489 : Assert(extension_id >= 0);
80 : :
81 : : /* If there is no array yet, create one. */
82 [ + - ]: 88489 : if (glob->extension_state == NULL)
83 : : {
84 : : MemoryContext planner_cxt;
85 : : Size sz;
86 : :
87 : 88489 : planner_cxt = GetMemoryChunkContext(glob);
88 : 88489 : glob->extension_state_allocated =
89 [ - + ]: 88489 : Max(4, pg_nextpower2_32(extension_id + 1));
90 : 88489 : sz = glob->extension_state_allocated * sizeof(void *);
91 : 88489 : glob->extension_state = MemoryContextAllocZero(planner_cxt, sz);
92 : : }
93 : :
94 : : /* If there's an array but it's currently full, expand it. */
95 [ - + ]: 88489 : if (extension_id >= glob->extension_state_allocated)
96 : : {
97 : : int i;
98 : :
324 rhaas@postgresql.org 99 :UBC 0 : i = pg_nextpower2_32(extension_id + 1);
260 michael@paquier.xyz 100 : 0 : glob->extension_state = repalloc0_array(glob->extension_state, void *,
101 : : glob->extension_state_allocated, i);
324 rhaas@postgresql.org 102 : 0 : glob->extension_state_allocated = i;
103 : : }
104 : :
324 rhaas@postgresql.org 105 :CBC 88489 : glob->extension_state[extension_id] = opaque;
106 : 88489 : }
107 : :
108 : : /*
109 : : * Store extension-specific state into a PlannerInfo.
110 : : */
111 : : void
112 : 70 : SetPlannerInfoExtensionState(PlannerInfo *root, int extension_id,
113 : : void *opaque)
114 : : {
115 [ - + ]: 70 : Assert(extension_id >= 0);
116 : :
117 : : /* If there is no array yet, create one. */
118 [ + + ]: 70 : if (root->extension_state == NULL)
119 : : {
120 : : Size sz;
121 : :
122 : 35 : root->extension_state_allocated =
123 [ - + ]: 35 : Max(4, pg_nextpower2_32(extension_id + 1));
124 : 35 : sz = root->extension_state_allocated * sizeof(void *);
125 : 35 : root->extension_state = MemoryContextAllocZero(root->planner_cxt, sz);
126 : : }
127 : :
128 : : /* If there's an array but it's currently full, expand it. */
129 [ - + ]: 70 : if (extension_id >= root->extension_state_allocated)
130 : : {
131 : : int i;
132 : :
324 rhaas@postgresql.org 133 :UBC 0 : i = pg_nextpower2_32(extension_id + 1);
260 michael@paquier.xyz 134 : 0 : root->extension_state = repalloc0_array(root->extension_state, void *,
135 : : root->extension_state_allocated, i);
324 rhaas@postgresql.org 136 : 0 : root->extension_state_allocated = i;
137 : : }
138 : :
324 rhaas@postgresql.org 139 :CBC 70 : root->extension_state[extension_id] = opaque;
140 : 70 : }
141 : :
142 : : /*
143 : : * Store extension-specific state into a RelOptInfo.
144 : : */
145 : : void
146 : 26785 : SetRelOptInfoExtensionState(RelOptInfo *rel, int extension_id,
147 : : void *opaque)
148 : : {
149 [ - + ]: 26785 : Assert(extension_id >= 0);
150 : :
151 : : /* If there is no array yet, create one. */
152 [ + - ]: 26785 : if (rel->extension_state == NULL)
153 : : {
154 : : MemoryContext planner_cxt;
155 : : Size sz;
156 : :
157 : 26785 : planner_cxt = GetMemoryChunkContext(rel);
158 : 26785 : rel->extension_state_allocated =
159 [ - + ]: 26785 : Max(4, pg_nextpower2_32(extension_id + 1));
160 : 26785 : sz = rel->extension_state_allocated * sizeof(void *);
161 : 26785 : rel->extension_state = MemoryContextAllocZero(planner_cxt, sz);
162 : : }
163 : :
164 : : /* If there's an array but it's currently full, expand it. */
165 [ - + ]: 26785 : if (extension_id >= rel->extension_state_allocated)
166 : : {
167 : : int i;
168 : :
324 rhaas@postgresql.org 169 :UBC 0 : i = pg_nextpower2_32(extension_id + 1);
260 michael@paquier.xyz 170 : 0 : rel->extension_state = repalloc0_array(rel->extension_state, void *,
171 : : rel->extension_state_allocated, i);
324 rhaas@postgresql.org 172 : 0 : rel->extension_state_allocated = i;
173 : : }
174 : :
324 rhaas@postgresql.org 175 :CBC 26785 : rel->extension_state[extension_id] = opaque;
176 : 26785 : }
|