Coverage Report

Created: 2026-11-12 07:20

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