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
70 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)
70 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. */
70 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 : : {
70 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. */
70 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
70 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);
6 michael@paquier.xyz 101 : 0 : glob->extension_state = repalloc0_array(glob->extension_state, void *,
102 : : glob->extension_state_allocated, i);
70 rhaas@postgresql.org 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
70 rhaas@postgresql.org 113 :GNC 42 : SetPlannerInfoExtensionState(PlannerInfo *root, int extension_id,
114 : : void *opaque)
115 : : {
116 [ - + ]: 42 : 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 : :
70 rhaas@postgresql.org 134 :UNC 0 : i = pg_nextpower2_32(extension_id + 1);
6 michael@paquier.xyz 135 : 0 : root->extension_state = repalloc0_array(root->extension_state, void *,
136 : : root->extension_state_allocated, i);
70 rhaas@postgresql.org 137 : 0 : root->extension_state_allocated = i;
138 : : }
139 : :
70 rhaas@postgresql.org 140 :GNC 42 : root->extension_state[extension_id] = opaque;
141 : 42 : }
142 : :
143 : : /*
144 : : * Store extension-specific state into a RelOptInfo.
145 : : */
146 : : void
70 rhaas@postgresql.org 147 :UNC 0 : SetRelOptInfoExtensionState(RelOptInfo *rel, int extension_id,
148 : : void *opaque)
149 : : {
150 [ # # ]: 0 : 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);
6 michael@paquier.xyz 171 : 0 : rel->extension_state = repalloc0_array(rel->extension_state, void *,
172 : : rel->extension_state_allocated, i);
70 rhaas@postgresql.org 173 : 0 : rel->extension_state_allocated = i;
174 : : }
175 : :
176 : 0 : rel->extension_state[extension_id] = opaque;
177 : 0 : }
|