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 = 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 84 : 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 84 : if (root->extension_state == NULL) 120 : { 121 : Size sz; 122 : 123 42 : root->extension_state_allocated = 124 42 : Max(4, pg_nextpower2_32(extension_id + 1)); 125 42 : sz = root->extension_state_allocated * sizeof(void *); 126 42 : root->extension_state = MemoryContextAllocZero(root->planner_cxt, sz); 127 : } 128 : 129 : /* If there's an array but it's currently full, expand it. */ 130 84 : 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 84 : root->extension_state[extension_id] = opaque; 141 84 : } 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 : }