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 41 12 : GetPlannerExtensionId(const char *extension_name) 42 : { 43 : /* Search for an existing extension by this name; if found, return ID. */ 44 12 : 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 12 : if (PlannerExtensionNameArray == NULL) 50 : { 51 12 : PlannerExtensionNamesAllocated = 16; 52 12 : PlannerExtensionNameArray = (const char **) 53 12 : MemoryContextAlloc(TopMemoryContext, 54 : PlannerExtensionNamesAllocated 55 : * sizeof(char *)); 56 : } 57 : 58 : /* If there's an array but it's currently full, expand it. */ 59 12 : 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 12 : PlannerExtensionNameArray[PlannerExtensionNamesAssigned] = extension_name; 70 12 : 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 = (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 115 84 : SetPlannerInfoExtensionState(PlannerInfo *root, int extension_id, 116 : void *opaque) 117 : { 118 : Assert(extension_id >= 0); 119 : 120 : /* If there is no array yet, create one. */ 121 84 : if (root->extension_state == NULL) 122 : { 123 : Size sz; 124 : 125 42 : root->extension_state_allocated = 126 42 : Max(4, pg_nextpower2_32(extension_id + 1)); 127 42 : sz = root->extension_state_allocated * sizeof(void *); 128 42 : root->extension_state = MemoryContextAllocZero(root->planner_cxt, sz); 129 : } 130 : 131 : /* If there's an array but it's currently full, expand it. */ 132 84 : if (extension_id >= root->extension_state_allocated) 133 : { 134 : int i; 135 : 136 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 : 144 84 : root->extension_state[extension_id] = opaque; 145 84 : } 146 : 147 : /* 148 : * Store extension-specific state into a RelOptInfo. 149 : */ 150 : void 151 0 : SetRelOptInfoExtensionState(RelOptInfo *rel, int extension_id, 152 : void *opaque) 153 : { 154 : 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 : }