PostgreSQL Source Code git master
Loading...
Searching...
No Matches
pgpa_walker.c File Reference
#include "postgres.h"
#include "pgpa_join.h"
#include "pgpa_planner.h"
#include "pgpa_scan.h"
#include "pgpa_walker.h"
#include "nodes/plannodes.h"
#include "parser/parsetree.h"
#include "utils/lsyscache.h"
Include dependency graph for pgpa_walker.c:

Go to the source code of this file.

Functions

static void pgpa_walk_recursively (pgpa_plan_walker_context *walker, Plan *plan, bool within_join_problem, pgpa_join_unroller *join_unroller, List *active_query_features, bool beneath_any_gather)
 
static Bitmapsetpgpa_process_unrolled_join (pgpa_plan_walker_context *walker, pgpa_unrolled_join *ujoin)
 
static pgpa_query_featurepgpa_add_feature (pgpa_plan_walker_context *walker, pgpa_qf_type type, Plan *plan)
 
static void pgpa_qf_add_rti (List *active_query_features, Index rti)
 
static void pgpa_qf_add_rtis (List *active_query_features, Bitmapset *relids)
 
static void pgpa_qf_add_plan_rtis (List *active_query_features, Plan *plan, List *rtable)
 
static bool pgpa_walker_join_order_matches (pgpa_unrolled_join *ujoin, Index rtable_length, pgpa_identifier *rt_identifiers, pgpa_advice_target *target, bool toplevel)
 
static bool pgpa_walker_join_order_matches_member (pgpa_join_member *member, Index rtable_length, pgpa_identifier *rt_identifiers, pgpa_advice_target *target)
 
static pgpa_scanpgpa_walker_find_scan (pgpa_plan_walker_context *walker, pgpa_scan_strategy strategy, Bitmapset *relids)
 
static bool pgpa_walker_index_target_matches_plan (pgpa_index_target *itarget, Plan *plan)
 
static bool pgpa_walker_contains_feature (pgpa_plan_walker_context *walker, pgpa_qf_type type, Bitmapset *relids)
 
static bool pgpa_walker_contains_join (pgpa_plan_walker_context *walker, pgpa_join_strategy strategy, Bitmapset *relids)
 
static bool pgpa_walker_contains_no_gather (pgpa_plan_walker_context *walker, Bitmapset *relids)
 
static void pgpa_classify_alternative_subplans (pgpa_plan_walker_context *walker, List *proots, List **chosen_proots, List **discarded_proots)
 
void pgpa_plan_walker (pgpa_plan_walker_context *walker, PlannedStmt *pstmt, List *proots)
 
void pgpa_add_future_feature (pgpa_plan_walker_context *walker, pgpa_qf_type type, Plan *plan)
 
ElidedNodepgpa_last_elided_node (PlannedStmt *pstmt, Plan *plan)
 
Bitmapsetpgpa_relids (Plan *plan)
 
Index pgpa_scanrelid (Plan *plan)
 
Bitmapsetpgpa_filter_out_join_relids (Bitmapset *relids, List *rtable)
 
bool pgpa_walker_would_advise (pgpa_plan_walker_context *walker, pgpa_identifier *rt_identifiers, pgpa_advice_tag_type tag, pgpa_advice_target *target)
 

Function Documentation

◆ pgpa_add_feature()

static pgpa_query_feature * pgpa_add_feature ( pgpa_plan_walker_context walker,
pgpa_qf_type  type,
Plan plan 
)
static

Definition at line 637 of file pgpa_walker.c.

639{
641
642 qf->type = type;
643 qf->plan = plan;
644
645 walker->query_features[qf->type] =
646 lappend(walker->query_features[qf->type], qf);
647
648 return qf;
649}
#define palloc0_object(type)
Definition fe_memutils.h:75
List * lappend(List *list, void *datum)
Definition list.c:339
#define plan(x)
Definition pg_regress.c:164
static int fb(int x)
const char * type

References fb(), lappend(), palloc0_object, plan, and type.

Referenced by pgpa_add_future_feature(), and pgpa_walk_recursively().

◆ pgpa_add_future_feature()

void pgpa_add_future_feature ( pgpa_plan_walker_context walker,
pgpa_qf_type  type,
Plan plan 
)

Definition at line 533 of file pgpa_walker.c.

535{
537
538 walker->future_query_features =
539 lappend(walker->future_query_features, qf);
540}
static pgpa_query_feature * pgpa_add_feature(pgpa_plan_walker_context *walker, pgpa_qf_type type, Plan *plan)

References fb(), lappend(), pgpa_add_feature(), plan, and type.

Referenced by pgpa_decompose_join().

◆ pgpa_classify_alternative_subplans()

static void pgpa_classify_alternative_subplans ( pgpa_plan_walker_context walker,
List proots,
List **  chosen_proots,
List **  discarded_proots 
)
static

Definition at line 1094 of file pgpa_walker.c.

1098{
1100
1101 /* Initialize both output lists to empty. */
1102 *chosen_proots = NIL;
1104
1105 /* Collect all scan RTIs. */
1106 for (int s = 0; s < NUM_PGPA_SCAN_STRATEGY; s++)
1107 foreach_ptr(pgpa_scan, scan, walker->scans[s])
1109
1110 /* Now classify each subplan. */
1112 {
1113 bool chosen = false;
1114
1115 /*
1116 * We're only interested in classifying subplans for which there are
1117 * alternatives.
1118 */
1119 if (!proot->is_alternative_plan)
1120 continue;
1121
1122 /*
1123 * A subplan has been chosen if any of its scan RTIs appear in the
1124 * final plan. This cannot be the case if it has no RT offset.
1125 */
1126 if (proot->has_rtoffset)
1127 {
1128 for (int rti = 1; rti <= proot->rid_array_size; rti++)
1129 {
1130 if (proot->rid_array[rti - 1].alias_name != NULL &&
1131 bms_is_member(proot->rtoffset + rti, all_scan_rtis))
1132 {
1133 chosen = true;
1134 break;
1135 }
1136 }
1137 }
1138
1139 /* Add it to the correct list. */
1140 if (chosen)
1142 else
1144 }
1145}
bool bms_is_member(int x, const Bitmapset *a)
Definition bitmapset.c:510
Bitmapset * bms_add_members(Bitmapset *a, const Bitmapset *b)
Definition bitmapset.c:901
#define NIL
Definition pg_list.h:68
#define foreach_ptr(type, var, lst)
Definition pg_list.h:501
#define NUM_PGPA_SCAN_STRATEGY
Definition pgpa_scan.h:68

References bms_add_members(), bms_is_member(), fb(), foreach_ptr, lappend(), NIL, and NUM_PGPA_SCAN_STRATEGY.

Referenced by pgpa_plan_walker().

◆ pgpa_filter_out_join_relids()

Bitmapset * pgpa_filter_out_join_relids ( Bitmapset relids,
List rtable 
)

Definition at line 616 of file pgpa_walker.c.

617{
618 int rti = -1;
619 Bitmapset *result = NULL;
620
621 while ((rti = bms_next_member(relids, rti)) >= 0)
622 {
623 RangeTblEntry *rte = rt_fetch(rti, rtable);
624
625 if (rte->rtekind != RTE_JOIN)
626 result = bms_add_member(result, rti);
627 }
628
629 return result;
630}
int bms_next_member(const Bitmapset *a, int prevbit)
Definition bitmapset.c:1290
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition bitmapset.c:799
@ RTE_JOIN
#define rt_fetch(rangetable_index, rangetable)
Definition parsetree.h:31

References bms_add_member(), bms_next_member(), fb(), rt_fetch, and RTE_JOIN.

Referenced by pgpa_build_scan(), pgpa_qf_add_plan_rtis(), and pgpa_walk_recursively().

◆ pgpa_last_elided_node()

ElidedNode * pgpa_last_elided_node ( PlannedStmt pstmt,
Plan plan 
)

Definition at line 549 of file pgpa_walker.c.

550{
551 ElidedNode *elided_node = NULL;
552
554 {
555 if (n->plan_node_id == plan->plan_node_id)
556 elided_node = n;
557 }
558
559 return elided_node;
560}
#define foreach_node(type, var, lst)
Definition pg_list.h:528
List * elidedNodes
Definition plannodes.h:156

References PlannedStmt::elidedNodes, fb(), foreach_node, and plan.

Referenced by pgpa_decompose_join(), and pgpa_descend_node().

◆ pgpa_plan_walker()

void pgpa_plan_walker ( pgpa_plan_walker_context walker,
PlannedStmt pstmt,
List proots 
)

Definition at line 76 of file pgpa_walker.c.

78{
79 ListCell *lc;
84
85 /* Initialization. */
87 walker->pstmt = pstmt;
88
89 /* Walk the main plan tree. */
90 pgpa_walk_recursively(walker, pstmt->planTree, false, NULL, NIL, false);
91
92 /* Main plan tree walk won't reach subplans, so walk those. */
93 foreach(lc, pstmt->subplans)
94 {
95 Plan *plan = lfirst(lc);
96
97 if (plan != NULL)
98 pgpa_walk_recursively(walker, plan, false, NULL, NIL, false);
99 }
100
101 /* Adjust RTIs from sj_unique_rels for the flattened range table. */
103 {
104 /* If there are no sj_unique_rels for this proot, we can skip it. */
105 if (proot->sj_unique_rels == NIL)
106 continue;
107
108 /* If this is a subplan, find the range table offset. */
109 if (!proot->has_rtoffset)
110 elog(ERROR, "no rtoffset for plan %s", proot->plan_name);
111
112 /* Offset each relid set by the proot's rtoffset. */
113 foreach_node(Bitmapset, relids, proot->sj_unique_rels)
114 {
115 int rtindex = -1;
117
118 while ((rtindex = bms_next_member(relids, rtindex)) >= 0)
120 rtindex + proot->rtoffset);
121
123 }
124 }
125
126 /*
127 * Remove any non-unique semijoin query features for which making the rel
128 * unique wasn't considered.
129 */
131 walker->query_features[PGPAQF_SEMIJOIN_NON_UNIQUE])
132 {
133 if (list_member(sj_unique_rtis, qf->relids))
135 }
137
138 /*
139 * If we find any cases where analysis of the Plan tree shows that the
140 * semijoin was made unique but this possibility was never observed to be
141 * considered during planning, then we have a bug somewhere.
142 */
144 walker->query_features[PGPAQF_SEMIJOIN_UNIQUE])
145 {
146 if (!list_member(sj_unique_rtis, qf->relids))
147 {
149
151 outBitmapset(&buf, qf->relids);
152 elog(ERROR,
153 "unique semijoin found for relids %s but not observed during planning",
154 buf.data);
155 }
156 }
157
158 /*
159 * It's possible for a Gather or Gather Merge query feature to find no
160 * RTIs when partitionwise aggregation is in use. We shouldn't emit
161 * something like GATHER_MERGE(()), so instead emit nothing. This means
162 * that we won't advise either GATHER or GATHER_MERGE or NO_GATHER in such
163 * cases, which might be something we want to improve in the future.
164 *
165 * (Should the Partial Aggregates in such a case be created in an
166 * UPPERREL_GROUP_AGG with a non-empty relid set? Right now that doesn't
167 * happen, but it seems like it would make life easier for us if it did.)
168 */
169 for (int t = 0; t < NUM_PGPA_QF_TYPES; ++t)
170 {
171 List *query_features = NIL;
172
173 foreach_ptr(pgpa_query_feature, qf, walker->query_features[t])
174 {
175 if (qf->relids != NULL)
176 query_features = lappend(query_features, qf);
177 else
179 }
180
181 walker->query_features[t] = query_features;
182 }
183
184 /* Classify alternative subplans. */
187
188 /*
189 * Figure out which of the discarded alternatives have a non-discarded
190 * alternative. Those are the ones for which we want to emit DO_NOT_SCAN
191 * advice. (If every alternative was discarded, then there's no point.)
192 */
194 {
195 bool some_alternative_chosen = false;
196
198 {
199 if (strings_equal_or_both_null(discarded_proot->alternative_plan_name,
200 chosen_proot->alternative_plan_name))
201 {
203 break;
204 }
205 }
206
208 {
209 for (int rti = 1; rti <= discarded_proot->rid_array_size; rti++)
210 {
211 pgpa_identifier *rid = &discarded_proot->rid_array[rti - 1];
212
213 if (rid->alias_name != NULL)
214 walker->do_not_scan_identifiers =
215 lappend(walker->do_not_scan_identifiers, rid);
216 }
217 }
218 }
219}
#define Assert(condition)
Definition c.h:943
#define ERROR
Definition elog.h:39
#define elog(elevel,...)
Definition elog.h:227
bool list_member(const List *list, const void *datum)
Definition list.c:661
void outBitmapset(StringInfo str, const Bitmapset *bms)
Definition outfuncs.c:331
#define lfirst(lc)
Definition pg_list.h:172
static char buf[DEFAULT_XLOG_SEG_SIZE]
static bool strings_equal_or_both_null(const char *a, const char *b)
static void pgpa_classify_alternative_subplans(pgpa_plan_walker_context *walker, List *proots, List **chosen_proots, List **discarded_proots)
static void pgpa_walk_recursively(pgpa_plan_walker_context *walker, Plan *plan, bool within_join_problem, pgpa_join_unroller *join_unroller, List *active_query_features, bool beneath_any_gather)
@ PGPAQF_GATHER
Definition pgpa_walker.h:45
@ PGPAQF_GATHER_MERGE
Definition pgpa_walker.h:46
@ PGPAQF_SEMIJOIN_UNIQUE
Definition pgpa_walker.h:48
@ PGPAQF_SEMIJOIN_NON_UNIQUE
Definition pgpa_walker.h:47
#define NUM_PGPA_QF_TYPES
Definition pgpa_walker.h:52
void initStringInfo(StringInfo str)
Definition stringinfo.c:97
Definition pg_list.h:54
struct Plan * planTree
Definition plannodes.h:99
List * subplans
Definition plannodes.h:129
const char * alias_name

References pgpa_identifier::alias_name, Assert, bms_add_member(), bms_next_member(), buf, elog, ERROR, fb(), foreach_node, foreach_ptr, initStringInfo(), lappend(), lfirst, list_member(), NIL, NUM_PGPA_QF_TYPES, outBitmapset(), pgpa_classify_alternative_subplans(), pgpa_walk_recursively(), PGPAQF_GATHER, PGPAQF_GATHER_MERGE, PGPAQF_SEMIJOIN_NON_UNIQUE, PGPAQF_SEMIJOIN_UNIQUE, plan, PlannedStmt::planTree, strings_equal_or_both_null(), and PlannedStmt::subplans.

Referenced by pgpa_planner_shutdown().

◆ pgpa_process_unrolled_join()

static Bitmapset * pgpa_process_unrolled_join ( pgpa_plan_walker_context walker,
pgpa_unrolled_join ujoin 
)
static

Definition at line 496 of file pgpa_walker.c.

498{
499 Bitmapset *all_relids = bms_copy(ujoin->outer.scan->relids);
500
501 /* If this fails, we didn't unroll properly. */
502 Assert(ujoin->outer.unrolled_join == NULL);
503
504 for (int k = 0; k < ujoin->ninner; ++k)
505 {
506 pgpa_join_member *member = &ujoin->inner[k];
507 Bitmapset *relids;
508
509 if (member->unrolled_join != NULL)
511 member->unrolled_join);
512 else
513 {
514 Assert(member->scan != NULL);
515 relids = member->scan->relids;
516 }
517 walker->join_strategies[ujoin->strategy[k]] =
518 lappend(walker->join_strategies[ujoin->strategy[k]], relids);
520 }
521
522 return all_relids;
523}
Bitmapset * bms_copy(const Bitmapset *a)
Definition bitmapset.c:122
static Bitmapset * pgpa_process_unrolled_join(pgpa_plan_walker_context *walker, pgpa_unrolled_join *ujoin)
struct pgpa_scan * scan
Definition pgpa_join.h:60
pgpa_unrolled_join * unrolled_join
Definition pgpa_join.h:61
Bitmapset * relids
Definition pgpa_scan.h:77

References Assert, bms_add_members(), bms_copy(), fb(), lappend(), pgpa_process_unrolled_join(), pgpa_scan::relids, pgpa_join_member::scan, and pgpa_join_member::unrolled_join.

Referenced by pgpa_process_unrolled_join(), and pgpa_walk_recursively().

◆ pgpa_qf_add_plan_rtis()

static void pgpa_qf_add_plan_rtis ( List active_query_features,
Plan plan,
List rtable 
)
static

Definition at line 680 of file pgpa_walker.c.

681{
682 Bitmapset *relids;
683 Index rti;
684
685 if ((relids = pgpa_relids(plan)) != NULL)
686 {
687 relids = pgpa_filter_out_join_relids(relids, rtable);
689 }
690 else if ((rti = pgpa_scanrelid(plan)) != 0)
692}
unsigned int Index
Definition c.h:698
Bitmapset * pgpa_filter_out_join_relids(Bitmapset *relids, List *rtable)
Bitmapset * pgpa_relids(Plan *plan)
static void pgpa_qf_add_rtis(List *active_query_features, Bitmapset *relids)
Index pgpa_scanrelid(Plan *plan)
static void pgpa_qf_add_rti(List *active_query_features, Index rti)

References fb(), pgpa_filter_out_join_relids(), pgpa_qf_add_rti(), pgpa_qf_add_rtis(), pgpa_relids(), pgpa_scanrelid(), and plan.

Referenced by pgpa_walk_recursively().

◆ pgpa_qf_add_rti()

static void pgpa_qf_add_rti ( List active_query_features,
Index  rti 
)
static

Definition at line 655 of file pgpa_walker.c.

656{
658 {
659 qf->relids = bms_add_member(qf->relids, rti);
660 }
661}

References bms_add_member(), fb(), and foreach_ptr.

Referenced by pgpa_qf_add_plan_rtis().

◆ pgpa_qf_add_rtis()

static void pgpa_qf_add_rtis ( List active_query_features,
Bitmapset relids 
)
static

Definition at line 667 of file pgpa_walker.c.

668{
670 {
671 qf->relids = bms_add_members(qf->relids, relids);
672 }
673}

References bms_add_members(), fb(), and foreach_ptr.

Referenced by pgpa_qf_add_plan_rtis(), and pgpa_walk_recursively().

◆ pgpa_relids()

Bitmapset * pgpa_relids ( Plan plan)

Definition at line 566 of file pgpa_walker.c.

567{
568 if (IsA(plan, Result))
569 return ((Result *) plan)->relids;
570 else if (IsA(plan, ForeignScan))
571 return ((ForeignScan *) plan)->fs_relids;
572 else if (IsA(plan, Append))
573 return ((Append *) plan)->apprelids;
574 else if (IsA(plan, MergeAppend))
575 return ((MergeAppend *) plan)->apprelids;
576
577 return NULL;
578}
#define IsA(nodeptr, _type_)
Definition nodes.h:164

References fb(), IsA, and plan.

Referenced by pgpa_build_scan(), and pgpa_qf_add_plan_rtis().

◆ pgpa_scanrelid()

Index pgpa_scanrelid ( Plan plan)

Definition at line 586 of file pgpa_walker.c.

587{
588 switch (nodeTag(plan))
589 {
590 case T_SeqScan:
591 case T_SampleScan:
592 case T_BitmapHeapScan:
593 case T_TidScan:
594 case T_TidRangeScan:
595 case T_SubqueryScan:
596 case T_FunctionScan:
597 case T_TableFuncScan:
598 case T_ValuesScan:
599 case T_CteScan:
601 case T_WorkTableScan:
602 case T_ForeignScan:
603 case T_CustomScan:
604 case T_IndexScan:
605 case T_IndexOnlyScan:
606 return ((Scan *) plan)->scanrelid;
607 default:
608 return 0;
609 }
610}
#define nodeTag(nodeptr)
Definition nodes.h:139

References fb(), nodeTag, and plan.

Referenced by pgpa_build_scan(), and pgpa_qf_add_plan_rtis().

◆ pgpa_walk_recursively()

static void pgpa_walk_recursively ( pgpa_plan_walker_context walker,
Plan plan,
bool  within_join_problem,
pgpa_join_unroller join_unroller,
List active_query_features,
bool  beneath_any_gather 
)
static

Definition at line 245 of file pgpa_walker.c.

250{
253 bool join_unroller_toplevel = false;
254 ListCell *lc;
257
259
260 /*
261 * Check the future_query_features list to see whether this was previously
262 * identified as a plan node that needs to be treated as a query feature.
263 * We must do this before handling elided nodes, because if there's an
264 * elided node associated with a future query feature, the RTIs associated
265 * with the elided node should be the only ones attributed to the query
266 * feature.
267 */
268 foreach_ptr(pgpa_query_feature, qf, walker->future_query_features)
269 {
270 if (qf->plan == plan)
271 {
274 walker->future_query_features =
275 list_delete_ptr(walker->future_query_features, qf);
276 break;
277 }
278 }
279
280 /*
281 * Find all elided nodes for this Plan node.
282 */
283 foreach_node(ElidedNode, n, walker->pstmt->elidedNodes)
284 {
285 if (n->plan_node_id == plan->plan_node_id)
287 }
288
289 /* If we found any elided_nodes, handle them. */
290 if (elided_nodes != NIL)
291 {
294
295 /*
296 * RTIs for the final -- and thus logically uppermost -- elided node
297 * should be collected for query features passed down by the caller.
298 * However, elided nodes act as barriers to query features, which
299 * means that (1) the remaining elided nodes, if any, should be
300 * ignored for purposes of query features and (2) the list of active
301 * query features should be reset to empty so that we do not add RTIs
302 * from the plan node that is logically beneath the elided node to the
303 * query features passed down from the caller.
304 */
308 walker->pstmt->rtable));
310
311 /*
312 * If we're within a join problem, the join_unroller is responsible
313 * for building the scan for the final elided node, so throw it out.
314 */
317
318 /* Build scans for all (or the remaining) elided nodes. */
320 {
321 (void) pgpa_build_scan(walker, plan, elided_node,
323 }
324
325 /*
326 * If there were any elided nodes, then everything beneath those nodes
327 * is not part of the same join problem.
328 *
329 * In more detail, if an Append or MergeAppend was elided, then a
330 * partitionwise join was chosen and only a single child survived; if
331 * a SubqueryScan was elided, the subquery was planned without
332 * flattening it into the parent.
333 */
334 within_join_problem = false;
336 }
337
338 /*
339 * If this is a Gather or Gather Merge node, directly add it to the list
340 * of currently-active query features. We must do this after handling
341 * elided nodes, since the Gather or Gather Merge node occurs logically
342 * beneath any associated elided nodes.
343 *
344 * Exception: We disregard any single_copy Gather nodes. These are created
345 * by debug_parallel_query, and having them affect the plan advice is
346 * counterproductive, as the result will be to advise the use of a real
347 * Gather node, rather than a single copy one.
348 */
349 if (IsA(plan, Gather) && !((Gather *) plan)->single_copy)
350 {
354 beneath_any_gather = true;
355 }
356 else if (IsA(plan, GatherMerge))
357 {
361 beneath_any_gather = true;
362 }
363
364 /*
365 * If we're within a join problem, the join unroller is responsible for
366 * building any required scan for this node. If not, we do it here.
367 */
370
371 /*
372 * If this join needs to be unrolled but there's no join unroller already
373 * available, create one.
374 */
376 {
379 within_join_problem = true;
380 }
381
382 /*
383 * If this join is to be unrolled, pgpa_unroll_join() will return the join
384 * unroller object that should be passed down when we recurse into the
385 * outer and inner sides of the plan.
386 */
387 if (join_unroller != NULL)
390
391 /* Add RTIs from the plan node to all active query features. */
393
394 /*
395 * Recurse into the outer and inner subtrees.
396 *
397 * As an exception, if this is a ForeignScan, don't recurse. postgres_fdw
398 * sometimes stores an EPQ recheck plan in plan->lefttree, but that's
399 * going to mention the same set of relations as the ForeignScan itself,
400 * and we have no way to emit advice targeting the EPQ case vs. the
401 * non-EPQ case. Moreover, it's not entirely clear what other FDWs might
402 * do with the left and right subtrees. Maybe some better handling is
403 * needed here, but for now, we just punt.
404 */
405 if (!IsA(plan, ForeignScan))
406 {
407 if (plan->lefttree != NULL)
411 if (plan->righttree != NULL)
415 }
416
417 /*
418 * If we created a join unroller up above, then it's also our join to use
419 * it to build the final pgpa_unrolled_join, and to destroy the object.
420 */
422 {
424
426 walker->toplevel_unrolled_joins =
427 lappend(walker->toplevel_unrolled_joins, ujoin);
430 }
431
432 /*
433 * Some plan types can have additional children. Nodes like Append that
434 * can have any number of children store them in a List; a SubqueryScan
435 * just has a field for a single additional Plan.
436 */
437 switch (nodeTag(plan))
438 {
439 case T_Append:
440 {
441 Append *aplan = (Append *) plan;
442
444 }
445 break;
446 case T_MergeAppend:
447 {
449
451 }
452 break;
453 case T_BitmapAnd:
454 extraplans = ((BitmapAnd *) plan)->bitmapplans;
455 break;
456 case T_BitmapOr:
457 extraplans = ((BitmapOr *) plan)->bitmapplans;
458 break;
459 case T_SubqueryScan:
460
461 /*
462 * We don't pass down active_query_features across here, because
463 * those are specific to a subquery level.
464 */
467 break;
468 case T_CustomScan:
469 extraplans = ((CustomScan *) plan)->custom_plans;
470 break;
471 default:
472 break;
473 }
474
475 /* If we found a list of extra children, iterate over it. */
476 foreach(lc, extraplans)
477 {
478 Plan *subplan = lfirst(lc);
479
480 pgpa_walk_recursively(walker, subplan, false, NULL, NIL,
482 }
483}
List * list_delete_ptr(List *list, void *datum)
Definition list.c:872
List * list_copy(const List *oldlist)
Definition list.c:1573
List * list_truncate(List *list, int new_size)
Definition list.c:631
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:331
pgpa_unrolled_join * pgpa_build_unrolled_join(pgpa_plan_walker_context *walker, pgpa_join_unroller *join_unroller)
Definition pgpa_join.c:230
void pgpa_unroll_join(pgpa_plan_walker_context *walker, Plan *plan, bool beneath_any_gather, pgpa_join_unroller *join_unroller, pgpa_join_unroller **outer_join_unroller, pgpa_join_unroller **inner_join_unroller)
Definition pgpa_join.c:105
void pgpa_destroy_join_unroller(pgpa_join_unroller *join_unroller)
Definition pgpa_join.c:295
pgpa_join_unroller * pgpa_create_join_unroller(void)
Definition pgpa_join.c:64
static bool pgpa_is_join(Plan *plan)
Definition pgpa_join.h:90
pgpa_scan * pgpa_build_scan(pgpa_plan_walker_context *walker, Plan *plan, ElidedNode *elided_node, bool beneath_any_gather, bool within_join_problem)
Definition pgpa_scan.c:44
static void pgpa_qf_add_plan_rtis(List *active_query_features, Plan *plan, List *rtable)
List * appendplans
Definition plannodes.h:409
List * mergeplans
Definition plannodes.h:444

References Append::appendplans, Assert, fb(), foreach_node, foreach_ptr, IsA, lappend(), lfirst, list_copy(), list_delete_ptr(), list_length(), list_nth(), list_truncate(), MergeAppend::mergeplans, NIL, nodeTag, pgpa_add_feature(), pgpa_build_scan(), pgpa_build_unrolled_join(), pgpa_create_join_unroller(), pgpa_destroy_join_unroller(), pgpa_filter_out_join_relids(), pgpa_is_join(), pgpa_process_unrolled_join(), pgpa_qf_add_plan_rtis(), pgpa_qf_add_rtis(), pgpa_unroll_join(), pgpa_walk_recursively(), PGPAQF_GATHER, PGPAQF_GATHER_MERGE, and plan.

Referenced by pgpa_plan_walker(), and pgpa_walk_recursively().

◆ pgpa_walker_contains_feature()

static bool pgpa_walker_contains_feature ( pgpa_plan_walker_context walker,
pgpa_qf_type  type,
Bitmapset relids 
)
static

Definition at line 1045 of file pgpa_walker.c.

1048{
1049 List *query_features = walker->query_features[type];
1050
1051 foreach_ptr(pgpa_query_feature, qf, query_features)
1052 {
1053 if (bms_equal(qf->relids, relids))
1054 return true;
1055 }
1056
1057 return false;
1058}
bool bms_equal(const Bitmapset *a, const Bitmapset *b)
Definition bitmapset.c:142

References bms_equal(), fb(), foreach_ptr, and type.

Referenced by pgpa_walker_would_advise().

◆ pgpa_walker_contains_join()

static bool pgpa_walker_contains_join ( pgpa_plan_walker_context walker,
pgpa_join_strategy  strategy,
Bitmapset relids 
)
static

Definition at line 1065 of file pgpa_walker.c.

1068{
1069 List *join_strategies = walker->join_strategies[strategy];
1070
1071 foreach_ptr(Bitmapset, jsrelids, join_strategies)
1072 {
1073 if (bms_equal(jsrelids, relids))
1074 return true;
1075 }
1076
1077 return false;
1078}

References bms_equal(), fb(), and foreach_ptr.

Referenced by pgpa_walker_would_advise().

◆ pgpa_walker_contains_no_gather()

static bool pgpa_walker_contains_no_gather ( pgpa_plan_walker_context walker,
Bitmapset relids 
)
static

Definition at line 1084 of file pgpa_walker.c.

1086{
1087 return bms_is_subset(relids, walker->no_gather_scans);
1088}
bool bms_is_subset(const Bitmapset *a, const Bitmapset *b)
Definition bitmapset.c:412

References bms_is_subset(), and fb().

Referenced by pgpa_walker_would_advise().

◆ pgpa_walker_find_scan()

static pgpa_scan * pgpa_walker_find_scan ( pgpa_plan_walker_context walker,
pgpa_scan_strategy  strategy,
Bitmapset relids 
)
static

Definition at line 1025 of file pgpa_walker.c.

1028{
1029 List *scans = walker->scans[strategy];
1030
1031 foreach_ptr(pgpa_scan, scan, scans)
1032 {
1033 if (bms_equal(scan->relids, relids))
1034 return scan;
1035 }
1036
1037 return NULL;
1038}

References bms_equal(), fb(), and foreach_ptr.

Referenced by pgpa_walker_would_advise().

◆ pgpa_walker_index_target_matches_plan()

static bool pgpa_walker_index_target_matches_plan ( pgpa_index_target itarget,
Plan plan 
)
static

Definition at line 882 of file pgpa_walker.c.

883{
884 Oid indexoid = InvalidOid;
885
886 /* Retrieve the index OID from the plan. */
887 if (IsA(plan, IndexScan))
888 indexoid = ((IndexScan *) plan)->indexid;
889 else if (IsA(plan, IndexOnlyScan))
890 indexoid = ((IndexOnlyScan *) plan)->indexid;
891 else
892 elog(ERROR, "unrecognized node type: %d", (int) nodeTag(plan));
893
894 /* Check whether schema name matches, if specified in index target. */
895 if (itarget->indnamespace != NULL)
896 {
897 Oid nspoid = get_rel_namespace(indexoid);
898 char *relnamespace = get_namespace_name_or_temp(nspoid);
899
900 if (strcmp(itarget->indnamespace, relnamespace) != 0)
901 return false;
902 }
903
904 /* Check whether relation name matches. */
905 return (strcmp(itarget->indname, get_rel_name(indexoid)) == 0);
906}
char * get_rel_name(Oid relid)
Definition lsyscache.c:2148
Oid get_rel_namespace(Oid relid)
Definition lsyscache.c:2172
char * get_namespace_name_or_temp(Oid nspid)
Definition lsyscache.c:3612
#define InvalidOid
unsigned int Oid
char * indnamespace
Definition pgpa_ast.h:38

References elog, ERROR, fb(), get_namespace_name_or_temp(), get_rel_name(), get_rel_namespace(), pgpa_index_target::indname, pgpa_index_target::indnamespace, InvalidOid, IsA, nodeTag, and plan.

Referenced by pgpa_walker_would_advise().

◆ pgpa_walker_join_order_matches()

static bool pgpa_walker_join_order_matches ( pgpa_unrolled_join ujoin,
Index  rtable_length,
pgpa_identifier rt_identifiers,
pgpa_advice_target target,
bool  toplevel 
)
static

Definition at line 912 of file pgpa_walker.c.

917{
918 int nchildren = list_length(target->children);
919
921
922 /* At toplevel, we allow a prefix match. */
923 if (toplevel)
924 {
925 if (nchildren > ujoin->ninner + 1)
926 return false;
927 }
928 else
929 {
930 if (nchildren != ujoin->ninner + 1)
931 return false;
932 }
933
934 /* Outermost rel must match. */
938 linitial(target->children)))
939 return false;
940
941 /* Each inner rel must match. */
942 for (int n = 0; n < nchildren - 1; ++n)
943 {
945
950 return false;
951 }
952
953 return true;
954}
#define linitial(l)
Definition pg_list.h:178
@ PGPA_TARGET_ORDERED_LIST
Definition pgpa_ast.h:28
static bool pgpa_walker_join_order_matches_member(pgpa_join_member *member, Index rtable_length, pgpa_identifier *rt_identifiers, pgpa_advice_target *target)
pgpa_target_type ttype
Definition pgpa_ast.h:49

References Assert, pgpa_advice_target::children, fb(), linitial, list_length(), list_nth(), PGPA_TARGET_ORDERED_LIST, pgpa_walker_join_order_matches_member(), and pgpa_advice_target::ttype.

Referenced by pgpa_walker_join_order_matches_member(), and pgpa_walker_would_advise().

◆ pgpa_walker_join_order_matches_member()

static bool pgpa_walker_join_order_matches_member ( pgpa_join_member member,
Index  rtable_length,
pgpa_identifier rt_identifiers,
pgpa_advice_target target 
)
static

Definition at line 960 of file pgpa_walker.c.

964{
965 Bitmapset *relids = NULL;
966
967 if (member->unrolled_join != NULL)
968 {
969 if (target->ttype != PGPA_TARGET_ORDERED_LIST)
970 return false;
974 target,
975 false);
976 }
977
978 Assert(member->scan != NULL);
979 switch (target->ttype)
980 {
982 /* Could only match an unrolled join */
983 return false;
984
986 {
988 {
989 Index rti;
990
993 &child_target->rid);
994 if (rti == 0)
995 return false;
996 relids = bms_add_member(relids, rti);
997 }
998 break;
999 }
1000
1002 {
1003 Index rti;
1004
1007 &target->rid);
1008 if (rti == 0)
1009 return false;
1010 relids = bms_make_singleton(rti);
1011 break;
1012 }
1013 }
1014
1015 return bms_equal(member->scan->relids, relids);
1016}
Bitmapset * bms_make_singleton(int x)
Definition bitmapset.c:216
@ PGPA_TARGET_UNORDERED_LIST
Definition pgpa_ast.h:29
@ PGPA_TARGET_IDENTIFIER
Definition pgpa_ast.h:27
Index pgpa_compute_rti_from_identifier(int rtable_length, pgpa_identifier *rt_identifiers, pgpa_identifier *rid)
static bool pgpa_walker_join_order_matches(pgpa_unrolled_join *ujoin, Index rtable_length, pgpa_identifier *rt_identifiers, pgpa_advice_target *target, bool toplevel)
pgpa_identifier rid
Definition pgpa_ast.h:58

References Assert, bms_add_member(), bms_equal(), bms_make_singleton(), pgpa_advice_target::children, fb(), foreach_ptr, pgpa_compute_rti_from_identifier(), PGPA_TARGET_IDENTIFIER, PGPA_TARGET_ORDERED_LIST, PGPA_TARGET_UNORDERED_LIST, pgpa_walker_join_order_matches(), pgpa_scan::relids, pgpa_advice_target::rid, pgpa_join_member::scan, pgpa_advice_target::ttype, and pgpa_join_member::unrolled_join.

Referenced by pgpa_walker_join_order_matches().

◆ pgpa_walker_would_advise()

bool pgpa_walker_would_advise ( pgpa_plan_walker_context walker,
pgpa_identifier rt_identifiers,
pgpa_advice_tag_type  tag,
pgpa_advice_target target 
)

Definition at line 703 of file pgpa_walker.c.

707{
708 Index rtable_length = list_length(walker->pstmt->rtable);
709 Bitmapset *relids = NULL;
710
711 if (tag == PGPA_TAG_JOIN_ORDER)
712 {
713 foreach_ptr(pgpa_unrolled_join, ujoin, walker->toplevel_unrolled_joins)
714 {
716 rt_identifiers, target, true))
717 return true;
718 }
719
720 return false;
721 }
722
723 /*
724 * DO_NOT_SCAN advice targets rels that may not be in the flat range table
725 * (e.g. MinMaxAgg losers), so pgpa_compute_rti_from_identifier won't work
726 * here. Instead, check directly against the do_not_scan_identifiers list.
727 */
728 if (tag == PGPA_TAG_DO_NOT_SCAN)
729 {
730 if (target->ttype != PGPA_TARGET_IDENTIFIER)
731 return false;
732 foreach_ptr(pgpa_identifier, rid, walker->do_not_scan_identifiers)
733 {
734 if (strcmp(rid->alias_name, target->rid.alias_name) == 0 &&
735 rid->occurrence == target->rid.occurrence &&
736 strings_equal_or_both_null(rid->partnsp,
737 target->rid.partnsp) &&
738 strings_equal_or_both_null(rid->partrel,
739 target->rid.partrel) &&
740 strings_equal_or_both_null(rid->plan_name,
741 target->rid.plan_name))
742 return true;
743 }
744 return false;
745 }
746
747 if (target->ttype == PGPA_TARGET_IDENTIFIER)
748 {
749 Index rti;
750
752 &target->rid);
753 if (rti == 0)
754 return false;
755 relids = bms_make_singleton(rti);
756 }
757 else
758 {
761 {
762 Index rti;
763
767 &child_target->rid);
768 if (rti == 0)
769 return false;
770 relids = bms_add_member(relids, rti);
771 }
772 }
773
774 switch (tag)
775 {
777 /* should have been handled above */
779 break;
781 /* should have been handled above */
783 break;
787 relids) != NULL;
791 relids) != NULL;
793 {
794 pgpa_scan *scan;
795
797 relids);
798 if (scan == NULL)
799 return false;
800
802 }
804 {
805 pgpa_scan *scan;
806
808 relids);
809 if (scan == NULL)
810 return false;
811
813 }
817 relids) != NULL;
821 relids) != NULL;
825 relids) != NULL;
826 case PGPA_TAG_GATHER:
829 relids);
833 relids);
837 relids);
841 relids);
845 relids);
849 relids);
853 relids);
857 relids);
861 relids);
865 relids);
868 }
869
870 /* should not get here */
871 return false;
872}
#define pg_unreachable()
Definition c.h:367
@ PGPA_TAG_INDEX_SCAN
Definition pgpa_ast.h:89
@ PGPA_TAG_NESTED_LOOP_MATERIALIZE
Definition pgpa_ast.h:93
@ PGPA_TAG_MERGE_JOIN_PLAIN
Definition pgpa_ast.h:92
@ PGPA_TAG_GATHER_MERGE
Definition pgpa_ast.h:86
@ PGPA_TAG_GATHER
Definition pgpa_ast.h:85
@ PGPA_TAG_NESTED_LOOP_MEMOIZE
Definition pgpa_ast.h:94
@ PGPA_TAG_SEMIJOIN_NON_UNIQUE
Definition pgpa_ast.h:98
@ PGPA_TAG_BITMAP_HEAP_SCAN
Definition pgpa_ast.h:82
@ PGPA_TAG_PARTITIONWISE
Definition pgpa_ast.h:97
@ PGPA_TAG_NO_GATHER
Definition pgpa_ast.h:96
@ PGPA_TAG_INDEX_ONLY_SCAN
Definition pgpa_ast.h:88
@ PGPA_TAG_SEQ_SCAN
Definition pgpa_ast.h:100
@ PGPA_TAG_HASH_JOIN
Definition pgpa_ast.h:87
@ PGPA_TAG_SEMIJOIN_UNIQUE
Definition pgpa_ast.h:99
@ PGPA_TAG_DO_NOT_SCAN
Definition pgpa_ast.h:83
@ PGPA_TAG_JOIN_ORDER
Definition pgpa_ast.h:90
@ PGPA_TAG_TID_SCAN
Definition pgpa_ast.h:101
@ PGPA_TAG_FOREIGN_JOIN
Definition pgpa_ast.h:84
@ PGPA_TAG_NESTED_LOOP_PLAIN
Definition pgpa_ast.h:95
@ PGPA_TAG_MERGE_JOIN_MATERIALIZE
Definition pgpa_ast.h:91
@ JSTRAT_MERGE_JOIN_PLAIN
Definition pgpa_join.h:29
@ JSTRAT_NESTED_LOOP_MATERIALIZE
Definition pgpa_join.h:32
@ JSTRAT_NESTED_LOOP_MEMOIZE
Definition pgpa_join.h:33
@ JSTRAT_HASH_JOIN
Definition pgpa_join.h:34
@ JSTRAT_NESTED_LOOP_PLAIN
Definition pgpa_join.h:31
@ JSTRAT_MERGE_JOIN_MATERIALIZE
Definition pgpa_join.h:30
@ PGPA_SCAN_SEQ
Definition pgpa_scan.h:58
@ PGPA_SCAN_INDEX
Definition pgpa_scan.h:61
@ PGPA_SCAN_INDEX_ONLY
Definition pgpa_scan.h:62
@ PGPA_SCAN_BITMAP_HEAP
Definition pgpa_scan.h:59
@ PGPA_SCAN_FOREIGN
Definition pgpa_scan.h:60
@ PGPA_SCAN_TID
Definition pgpa_scan.h:64
@ PGPA_SCAN_PARTITIONWISE
Definition pgpa_scan.h:63
static bool pgpa_walker_contains_feature(pgpa_plan_walker_context *walker, pgpa_qf_type type, Bitmapset *relids)
static pgpa_scan * pgpa_walker_find_scan(pgpa_plan_walker_context *walker, pgpa_scan_strategy strategy, Bitmapset *relids)
static bool pgpa_walker_contains_no_gather(pgpa_plan_walker_context *walker, Bitmapset *relids)
static bool pgpa_walker_contains_join(pgpa_plan_walker_context *walker, pgpa_join_strategy strategy, Bitmapset *relids)
static bool pgpa_walker_index_target_matches_plan(pgpa_index_target *itarget, Plan *plan)
pgpa_index_target * itarget
Definition pgpa_ast.h:64
const char * partnsp
const char * partrel
const char * plan_name
Plan * plan
Definition pgpa_scan.h:75

References pgpa_identifier::alias_name, Assert, bms_add_member(), bms_make_singleton(), pgpa_advice_target::children, fb(), foreach_ptr, pgpa_advice_target::itarget, JSTRAT_HASH_JOIN, JSTRAT_MERGE_JOIN_MATERIALIZE, JSTRAT_MERGE_JOIN_PLAIN, JSTRAT_NESTED_LOOP_MATERIALIZE, JSTRAT_NESTED_LOOP_MEMOIZE, JSTRAT_NESTED_LOOP_PLAIN, list_length(), pgpa_identifier::occurrence, pgpa_identifier::partnsp, pgpa_identifier::partrel, pg_unreachable, pgpa_compute_rti_from_identifier(), PGPA_SCAN_BITMAP_HEAP, PGPA_SCAN_FOREIGN, PGPA_SCAN_INDEX, PGPA_SCAN_INDEX_ONLY, PGPA_SCAN_PARTITIONWISE, PGPA_SCAN_SEQ, PGPA_SCAN_TID, PGPA_TAG_BITMAP_HEAP_SCAN, PGPA_TAG_DO_NOT_SCAN, PGPA_TAG_FOREIGN_JOIN, PGPA_TAG_GATHER, PGPA_TAG_GATHER_MERGE, PGPA_TAG_HASH_JOIN, PGPA_TAG_INDEX_ONLY_SCAN, PGPA_TAG_INDEX_SCAN, PGPA_TAG_JOIN_ORDER, PGPA_TAG_MERGE_JOIN_MATERIALIZE, PGPA_TAG_MERGE_JOIN_PLAIN, PGPA_TAG_NESTED_LOOP_MATERIALIZE, PGPA_TAG_NESTED_LOOP_MEMOIZE, PGPA_TAG_NESTED_LOOP_PLAIN, PGPA_TAG_NO_GATHER, PGPA_TAG_PARTITIONWISE, PGPA_TAG_SEMIJOIN_NON_UNIQUE, PGPA_TAG_SEMIJOIN_UNIQUE, PGPA_TAG_SEQ_SCAN, PGPA_TAG_TID_SCAN, PGPA_TARGET_IDENTIFIER, PGPA_TARGET_ORDERED_LIST, pgpa_walker_contains_feature(), pgpa_walker_contains_join(), pgpa_walker_contains_no_gather(), pgpa_walker_find_scan(), pgpa_walker_index_target_matches_plan(), pgpa_walker_join_order_matches(), PGPAQF_GATHER, PGPAQF_GATHER_MERGE, PGPAQF_SEMIJOIN_NON_UNIQUE, PGPAQF_SEMIJOIN_UNIQUE, pgpa_scan::plan, pgpa_identifier::plan_name, pgpa_advice_target::rid, strings_equal_or_both_null(), and pgpa_advice_target::ttype.

Referenced by pgpa_planner_append_feedback().