PostgreSQL Source Code git master
Loading...
Searching...
No Matches
pgpa_identifier.h File Reference
#include "nodes/pathnodes.h"
#include "nodes/plannodes.h"
Include dependency graph for pgpa_identifier.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  pgpa_identifier
 

Typedefs

typedef struct pgpa_identifier pgpa_identifier
 

Functions

static bool strings_equal_or_both_null (const char *a, const char *b)
 
const charpgpa_identifier_string (const pgpa_identifier *rid)
 
void pgpa_compute_identifier_by_rti (PlannerInfo *root, Index rti, pgpa_identifier *rid)
 
int pgpa_compute_identifiers_by_relids (PlannerInfo *root, Bitmapset *relids, pgpa_identifier *rids)
 
pgpa_identifierpgpa_create_identifiers_for_planned_stmt (PlannedStmt *pstmt)
 
Index pgpa_compute_rti_from_identifier (int rtable_length, pgpa_identifier *rt_identifiers, pgpa_identifier *rid)
 

Typedef Documentation

◆ pgpa_identifier

Function Documentation

◆ pgpa_compute_identifier_by_rti()

void pgpa_compute_identifier_by_rti ( PlannerInfo root,
Index  rti,
pgpa_identifier rid 
)
extern

Definition at line 115 of file pgpa_identifier.c.

117{
118 Index top_rti = rti;
119 int occurrence = 1;
122 char *partnsp = NULL;
123 char *partrel = NULL;
124
125 /*
126 * If this is a child RTE, find the topmost parent that is still of type
127 * RTE_RELATION. We do this because we identify children of partitioned
128 * tables by the name of the child table, but subqueries can also have
129 * child rels and we don't care about those here.
130 */
131 for (;;)
132 {
135
136 /* append_rel_array can be NULL if there are no children */
137 if (root->append_rel_array == NULL ||
138 (appinfo = root->append_rel_array[top_rti]) == NULL)
139 break;
140
141 parent_rte = rt_fetch(appinfo->parent_relid, root->parse->rtable);
142 if (parent_rte->rtekind != RTE_RELATION)
143 break;
144
145 top_rti = appinfo->parent_relid;
146 }
147
148 /* Get the range table entries for the RTI and top RTI. */
149 rte = rt_fetch(rti, root->parse->rtable);
150 top_rte = rt_fetch(top_rti, root->parse->rtable);
151 Assert(rte->rtekind != RTE_JOIN);
152 Assert(top_rte->rtekind != RTE_JOIN);
153
154 /* Work out the correct occurrence number. */
156 {
159
160 /*
161 * If this is a child rel of a parent that is a relation, skip it.
162 *
163 * Such range table entries are disambiguated by mentioning the schema
164 * and name of the table, not by counting them as separate occurrences
165 * of the same table.
166 *
167 * NB: append_rel_array can be NULL if there are no children
168 */
169 if (root->append_rel_array != NULL &&
170 (appinfo = root->append_rel_array[prior_rti]) != NULL)
171 {
173
174 parent_rte = rt_fetch(appinfo->parent_relid, root->parse->rtable);
175 if (parent_rte->rtekind == RTE_RELATION)
176 continue;
177 }
178
179 /* Skip NULL entries and joins. */
180 prior_rte = rt_fetch(prior_rti, root->parse->rtable);
181 if (prior_rte == NULL || prior_rte->rtekind == RTE_JOIN)
182 continue;
183
184 /* Skip if the alias name differs. */
185 if (strcmp(prior_rte->eref->aliasname, rte->eref->aliasname) != 0)
186 continue;
187
188 /* Looks like a true duplicate. */
189 ++occurrence;
190 }
191
192 /* If this is a child table, get the schema and relation names. */
193 if (rti != top_rti)
194 {
196 partrel = get_rel_name(rte->relid);
197 }
198
199 /* OK, we have all the answers we need. Return them to the caller. */
200 rid->alias_name = top_rte->eref->aliasname;
201 rid->occurrence = occurrence;
202 rid->partnsp = partnsp;
203 rid->partrel = partrel;
204 rid->plan_name = root->plan_name;
205}
#define Assert(condition)
Definition c.h:927
unsigned int Index
Definition c.h:682
char * get_rel_name(Oid relid)
Definition lsyscache.c:2146
Oid get_rel_namespace(Oid relid)
Definition lsyscache.c:2170
char * get_namespace_name_or_temp(Oid nspid)
Definition lsyscache.c:3610
@ RTE_JOIN
@ RTE_RELATION
#define rt_fetch(rangetable_index, rangetable)
Definition parsetree.h:31
static int fb(int x)
tree ctl root
Definition radixtree.h:1857
const char * alias_name
const char * partnsp
const char * partrel
const char * plan_name

References pgpa_identifier::alias_name, Assert, fb(), get_namespace_name_or_temp(), get_rel_name(), get_rel_namespace(), pgpa_identifier::occurrence, pgpa_identifier::partnsp, pgpa_identifier::partrel, pgpa_identifier::plan_name, root, rt_fetch, RTE_JOIN, and RTE_RELATION.

Referenced by pgpa_build_simple_rel(), pgpa_compute_identifiers_by_relids(), and pgpa_ri_checker_save().

◆ pgpa_compute_identifiers_by_relids()

int pgpa_compute_identifiers_by_relids ( PlannerInfo root,
Bitmapset relids,
pgpa_identifier rids 
)
extern

Definition at line 220 of file pgpa_identifier.c.

222{
223 int count = 0;
224 int rti = -1;
225
226 while ((rti = bms_next_member(relids, rti)) >= 0)
227 {
228 RangeTblEntry *rte = rt_fetch(rti, root->parse->rtable);
229
230 if (rte->rtekind == RTE_JOIN)
231 continue;
232 pgpa_compute_identifier_by_rti(root, rti, &rids[count++]);
233 }
234
235 Assert(count > 0);
236 return count;
237}
int bms_next_member(const Bitmapset *a, int prevbit)
Definition bitmapset.c:1290
void pgpa_compute_identifier_by_rti(PlannerInfo *root, Index rti, pgpa_identifier *rid)

References Assert, bms_next_member(), fb(), pgpa_compute_identifier_by_rti(), root, rt_fetch, and RTE_JOIN.

Referenced by pgpa_get_join_state().

◆ pgpa_compute_rti_from_identifier()

Index pgpa_compute_rti_from_identifier ( int  rtable_length,
pgpa_identifier rt_identifiers,
pgpa_identifier rid 
)
extern

Definition at line 352 of file pgpa_identifier.c.

355{
356 Index result = 0;
357
358 for (Index rti = 1; rti <= rtable_length; ++rti)
359 {
361
362 /* If there's no identifier for this RTI, skip it. */
363 if (rti_rid->alias_name == NULL)
364 continue;
365
366 /*
367 * If it matches, return this RTI. As usual, an omitted partition
368 * schema matches anything, but partition and plan names must either
369 * match exactly or be omitted on both sides.
370 */
371 if (strcmp(rid->alias_name, rti_rid->alias_name) == 0 &&
372 rid->occurrence == rti_rid->occurrence &&
373 (rid->partnsp == NULL || rti_rid->partnsp == NULL ||
374 strcmp(rid->partnsp, rti_rid->partnsp) == 0) &&
377 {
378 if (result != 0)
379 {
380 /* Multiple matches were found. */
381 return 0;
382 }
383 result = rti;
384 }
385 }
386
387 return result;
388}
static bool strings_equal_or_both_null(const char *a, const char *b)

References pgpa_identifier::alias_name, fb(), pgpa_identifier::occurrence, pgpa_identifier::partnsp, pgpa_identifier::partrel, pgpa_identifier::plan_name, and strings_equal_or_both_null().

Referenced by pgpa_walker_join_order_matches_member(), and pgpa_walker_would_advise().

◆ pgpa_create_identifiers_for_planned_stmt()

pgpa_identifier * pgpa_create_identifiers_for_planned_stmt ( PlannedStmt pstmt)
extern

Definition at line 244 of file pgpa_identifier.c.

245{
249 int rtinfoindex = 0;
252
253 /*
254 * Account for relations added by inheritance expansion of partitioned
255 * tables.
256 */
258 pstmt->appendRelations);
259
260 /*
261 * When we begin iterating, we're processing the portion of the range
262 * table that originated from the top-level PlannerInfo, so subrtinfo is
263 * NULL. Later, subrtinfo will be the SubPlanRTInfo for the subquery whose
264 * portion of the range table we are processing. nextrtinfo is always the
265 * SubPlanRTInfo that follows the current one, if any, so when we're
266 * processing the top-level query's portion of the range table, the next
267 * SubPlanRTInfo is the very first one.
268 */
269 if (pstmt->subrtinfos != NULL)
271
272 /* Main loop over the range table. */
273 for (Index rti = 1; rti <= rtable_length; rti++)
274 {
275 const char *plan_name;
279 char *partnsp = NULL;
280 char *partrel = NULL;
281 int occurrence;
282 pgpa_identifier *rid;
283
284 /*
285 * Advance to the next SubPlanRTInfo, if it's time to do that.
286 *
287 * This loop probably shouldn't ever iterate more than once, because
288 * that would imply that a subquery was planned but added nothing to
289 * the range table; but let's be defensive and assume it can happen.
290 */
291 while (nextrtinfo != NULL && rti > nextrtinfo->rtoffset)
292 {
294 if (++rtinfoindex >= list_length(pstmt->subrtinfos))
296 else
298 }
299
300 /* Fetch the range table entry, if any. */
301 rte = rt_fetch(rti, pstmt->rtable);
302
303 /*
304 * We can't and don't need to identify null entries, and we don't want
305 * to identify join entries.
306 */
307 if (rte == NULL || rte->rtekind == RTE_JOIN)
308 continue;
309
310 /*
311 * If this is not a relation added by partitioned table expansion,
312 * then the top RTI/RTE are just the same as this RTI/RTE. Otherwise,
313 * we need the information for the top RTI/RTE, and must also fetch
314 * the partition schema and name.
315 */
316 top_rti = top_rti_map[rti - 1];
317 if (rti == top_rti)
318 top_rte = rte;
319 else
320 {
321 top_rte = rt_fetch(top_rti, pstmt->rtable);
322 partnsp =
324 partrel = get_rel_name(rte->relid);
325 }
326
327 /* Compute the correct occurrence number. */
328 occurrence = pgpa_occurrence_number(pstmt->rtable, top_rti_map,
329 rtinfo, top_rti);
330
331 /* Get the name of the current plan (NULL for toplevel query). */
332 plan_name = rtinfo == NULL ? NULL : rtinfo->plan_name;
333
334 /* Save all the details we've derived. */
335 rid = &result[rti - 1];
336 rid->alias_name = top_rte->eref->aliasname;
337 rid->occurrence = occurrence;
338 rid->partnsp = partnsp;
339 rid->partrel = partrel;
340 rid->plan_name = plan_name;
341 }
342
343 return result;
344}
#define palloc0_array(type, count)
Definition fe_memutils.h:77
static int list_length(const List *l)
Definition pg_list.h:152
static void * list_nth(const List *list, int n)
Definition pg_list.h:299
#define linitial(l)
Definition pg_list.h:178
static int pgpa_occurrence_number(List *rtable, Index *top_rti_map, SubPlanRTInfo *rtinfo, Index rti)
static Index * pgpa_create_top_rti_map(Index rtable_length, List *rtable, List *appinfos)
List * appendRelations
Definition plannodes.h:127
List * subrtinfos
Definition plannodes.h:135
List * rtable
Definition plannodes.h:109

References pgpa_identifier::alias_name, PlannedStmt::appendRelations, fb(), get_namespace_name_or_temp(), get_rel_name(), get_rel_namespace(), linitial, list_length(), list_nth(), pgpa_identifier::occurrence, palloc0_array, pgpa_identifier::partnsp, pgpa_identifier::partrel, pgpa_create_top_rti_map(), pgpa_occurrence_number(), pgpa_identifier::plan_name, rt_fetch, PlannedStmt::rtable, RTE_JOIN, and PlannedStmt::subrtinfos.

Referenced by pgpa_planner_shutdown(), and pgpa_ri_checker_validate().

◆ pgpa_identifier_string()

const char * pgpa_identifier_string ( const pgpa_identifier rid)
extern

Definition at line 80 of file pgpa_identifier.c.

81{
82 const char *result;
83
84 Assert(rid->alias_name != NULL);
85 result = quote_identifier(rid->alias_name);
86
87 Assert(rid->occurrence >= 0);
88 if (rid->occurrence > 1)
89 result = psprintf("%s#%d", result, rid->occurrence);
90
91 if (rid->partrel != NULL)
92 {
93 if (rid->partnsp == NULL)
94 result = psprintf("%s/%s", result,
96 else
97 result = psprintf("%s/%s.%s", result,
100 }
101
102 if (rid->plan_name != NULL)
103 result = psprintf("%s@%s", result, quote_identifier(rid->plan_name));
104
105 return result;
106}
char * psprintf(const char *fmt,...)
Definition psprintf.c:43
const char * quote_identifier(const char *ident)

References pgpa_identifier::alias_name, Assert, fb(), pgpa_identifier::occurrence, pgpa_identifier::partnsp, pgpa_identifier::partrel, pgpa_identifier::plan_name, psprintf(), and quote_identifier().

Referenced by pgpa_format_advice_target(), pgpa_output_advice(), pgpa_ri_checker_save(), and pgpa_ri_checker_validate().

◆ strings_equal_or_both_null()

static bool strings_equal_or_both_null ( const char a,
const char b 
)
inlinestatic

Definition at line 30 of file pgpa_identifier.h.

31{
32 if (a == b)
33 return true;
34 else if (a == NULL || b == NULL)
35 return false;
36 else
37 return strcmp(a, b) == 0;
38}
int b
Definition isn.c:74
int a
Definition isn.c:73

References a, b, and fb().

Referenced by pgpa_compute_rti_from_identifier(), pgpa_identifier_matches_target(), pgpa_trove_entry_compare_key(), and pgpa_trove_lookup().