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

Go to the source code of this file.

Functions

static pgpa_scanpgpa_make_scan (pgpa_plan_walker_context *walker, Plan *plan, pgpa_scan_strategy strategy, Bitmapset *relids)
 
static RTEKind unique_nonjoin_rtekind (Bitmapset *relids, List *rtable)
 
pgpa_scanpgpa_build_scan (pgpa_plan_walker_context *walker, Plan *plan, ElidedNode *elided_node, bool beneath_any_gather, bool within_join_problem)
 

Function Documentation

◆ pgpa_build_scan()

pgpa_scan * pgpa_build_scan ( pgpa_plan_walker_context walker,
Plan plan,
ElidedNode elided_node,
bool  beneath_any_gather,
bool  within_join_problem 
)

Definition at line 44 of file pgpa_scan.c.

47{
49 Bitmapset *relids = NULL;
50 int rti = -1;
51 List *child_append_relid_sets = NIL;
53
54 if (elided_node != NULL)
55 {
56 nodetype = elided_node->elided_type;
57 relids = elided_node->relids;
58
59 /*
60 * If setrefs processing elided an Append or MergeAppend node that had
61 * only one surviving child, it could be either a partitionwise
62 * operation or a setop over subqueries, depending on the rtekind.
63 *
64 * A setop over subqueries, or a trivial SubqueryScan that was elided,
65 * is an "ordinary" scan i.e. one for which we do not need to generate
66 * advice because the planner has not made any meaningful choice.
67 *
68 * Note that the PGPA_SCAN_PARTITIONWISE case also includes
69 * partitionwise joins; this module considers those to be a form of
70 * scan, since they lack internal structure that we can decompose.
71 */
72 if ((nodetype == T_Append || nodetype == T_MergeAppend) &&
74 walker->pstmt->rtable) == RTE_RELATION)
75 strategy = PGPA_SCAN_PARTITIONWISE;
76 else
77 strategy = PGPA_SCAN_ORDINARY;
78
79 /* Join RTIs can be present, but advice never refers to them. */
80 relids = pgpa_filter_out_join_relids(relids, walker->pstmt->rtable);
81 }
82 else if ((rti = pgpa_scanrelid(plan)) != 0)
83 {
84 relids = bms_make_singleton(rti);
85
86 switch (nodeTag(plan))
87 {
88 case T_SeqScan:
89 strategy = PGPA_SCAN_SEQ;
90 break;
92 strategy = PGPA_SCAN_BITMAP_HEAP;
93 break;
94 case T_IndexScan:
95 strategy = PGPA_SCAN_INDEX;
96 break;
97 case T_IndexOnlyScan:
98 strategy = PGPA_SCAN_INDEX_ONLY;
99 break;
100 case T_TidScan:
101 case T_TidRangeScan:
102 strategy = PGPA_SCAN_TID;
103 break;
104 default:
105
106 /*
107 * This case includes a ForeignScan targeting a single
108 * relation; no other strategy is possible in that case, but
109 * see below, where things are different in multi-relation
110 * cases.
111 */
112 strategy = PGPA_SCAN_ORDINARY;
113 break;
114 }
115 }
116 else if ((relids = pgpa_relids(plan)) != NULL)
117 {
118 switch (nodeTag(plan))
119 {
120 case T_ForeignScan:
121
122 /*
123 * If multiple relations are being targeted by a single
124 * foreign scan, then the foreign join has been pushed to the
125 * remote side, and we want that to be reflected in the
126 * generated advice.
127 */
128 strategy = PGPA_SCAN_FOREIGN;
129 break;
130 case T_Append:
131
132 /*
133 * Append nodes can represent partitionwise scans of a
134 * relation, but when they implement a set operation, they are
135 * just ordinary scans.
136 */
137 if (unique_nonjoin_rtekind(relids, walker->pstmt->rtable)
138 == RTE_RELATION)
139 strategy = PGPA_SCAN_PARTITIONWISE;
140 else
141 strategy = PGPA_SCAN_ORDINARY;
142
143 /* Be sure to account for pulled-up scans. */
144 child_append_relid_sets =
145 ((Append *) plan)->child_append_relid_sets;
146 break;
147 case T_MergeAppend:
148 /* Same logic here as for Append, above. */
149 if (unique_nonjoin_rtekind(relids, walker->pstmt->rtable)
150 == RTE_RELATION)
151 strategy = PGPA_SCAN_PARTITIONWISE;
152 else
153 strategy = PGPA_SCAN_ORDINARY;
154
155 /* Be sure to account for pulled-up scans. */
156 child_append_relid_sets =
157 ((MergeAppend *) plan)->child_append_relid_sets;
158 break;
159 default:
160 strategy = PGPA_SCAN_ORDINARY;
161 break;
162 }
163
164
165 /* Join RTIs can be present, but advice never refers to them. */
166 relids = pgpa_filter_out_join_relids(relids, walker->pstmt->rtable);
167 }
168
169 /*
170 * If this is an Append or MergeAppend node into which subordinate Append
171 * or MergeAppend paths were merged, each of those merged paths is
172 * effectively another scan for which we need to account.
173 */
174 foreach_node(Bitmapset, child_relids, child_append_relid_sets)
175 {
177
179 pgpa_filter_out_join_relids(child_relids,
180 walker->pstmt->rtable);
181 (void) pgpa_make_scan(walker, plan, strategy,
183 }
184
185 /*
186 * If this plan node has no associated RTIs, it's not a scan. When the
187 * 'within_join_problem' flag is set, that's unexpected, so throw an
188 * error, else return quietly.
189 */
190 if (relids == NULL)
191 {
193 elog(ERROR, "plan node has no RTIs: %d", (int) nodeTag(plan));
194 return NULL;
195 }
196
197 /*
198 * Add the appropriate set of RTIs to walker->no_gather_scans.
199 *
200 * Add nothing if we're beneath a Gather or Gather Merge node, since
201 * NO_GATHER advice is clearly inappropriate in that situation.
202 *
203 * Add nothing if this is an Append or MergeAppend node, whether or not
204 * elided. We'll emit NO_GATHER() for the underlying scan, which is good
205 * enough.
206 */
209 walker->no_gather_scans =
210 bms_add_members(walker->no_gather_scans, relids);
211
212 /* Caller tells us whether NO_GATHER() advice for this scan is needed. */
213 return pgpa_make_scan(walker, plan, strategy, relids);
214}
Bitmapset * bms_make_singleton(int x)
Definition bitmapset.c:216
Bitmapset * bms_add_members(Bitmapset *a, const Bitmapset *b)
Definition bitmapset.c:901
#define ERROR
Definition elog.h:39
#define elog(elevel,...)
Definition elog.h:226
#define nodeTag(nodeptr)
Definition nodes.h:139
NodeTag
Definition nodes.h:27
@ RTE_RELATION
#define NIL
Definition pg_list.h:68
#define foreach_node(type, var, lst)
Definition pg_list.h:496
#define plan(x)
Definition pg_regress.c:161
static RTEKind unique_nonjoin_rtekind(Bitmapset *relids, List *rtable)
Definition pgpa_scan.c:242
static pgpa_scan * pgpa_make_scan(pgpa_plan_walker_context *walker, Plan *plan, pgpa_scan_strategy strategy, Bitmapset *relids)
Definition pgpa_scan.c:220
pgpa_scan_strategy
Definition pgpa_scan.h:56
@ 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
@ PGPA_SCAN_ORDINARY
Definition pgpa_scan.h:57
Bitmapset * pgpa_filter_out_join_relids(Bitmapset *relids, List *rtable)
Bitmapset * pgpa_relids(Plan *plan)
Index pgpa_scanrelid(Plan *plan)
static int fb(int x)
NodeTag elided_type
Definition plannodes.h:1870
Bitmapset * relids
Definition plannodes.h:1871
Definition pg_list.h:54

References bms_add_members(), bms_make_singleton(), ElidedNode::elided_type, elog, ERROR, fb(), foreach_node, NIL, nodeTag, pgpa_filter_out_join_relids(), pgpa_make_scan(), pgpa_relids(), PGPA_SCAN_BITMAP_HEAP, PGPA_SCAN_FOREIGN, PGPA_SCAN_INDEX, PGPA_SCAN_INDEX_ONLY, PGPA_SCAN_ORDINARY, PGPA_SCAN_PARTITIONWISE, PGPA_SCAN_SEQ, PGPA_SCAN_TID, pgpa_scanrelid(), plan, ElidedNode::relids, RTE_RELATION, and unique_nonjoin_rtekind().

Referenced by pgpa_build_unrolled_join(), and pgpa_walk_recursively().

◆ pgpa_make_scan()

static pgpa_scan * pgpa_make_scan ( pgpa_plan_walker_context walker,
Plan plan,
pgpa_scan_strategy  strategy,
Bitmapset relids 
)
static

Definition at line 220 of file pgpa_scan.c.

222{
223 pgpa_scan *scan;
224
225 /* Create the scan object. */
226 scan = palloc(sizeof(pgpa_scan));
227 scan->plan = plan;
228 scan->strategy = strategy;
229 scan->relids = relids;
230
231 /* Add it to the appropriate list. */
232 walker->scans[scan->strategy] = lappend(walker->scans[scan->strategy],
233 scan);
234
235 return scan;
236}
List * lappend(List *list, void *datum)
Definition list.c:339
void * palloc(Size size)
Definition mcxt.c:1387
Plan * plan
Definition pgpa_scan.h:75
pgpa_scan_strategy strategy
Definition pgpa_scan.h:76
Bitmapset * relids
Definition pgpa_scan.h:77

References fb(), lappend(), palloc(), pgpa_scan::plan, plan, pgpa_scan::relids, and pgpa_scan::strategy.

Referenced by pgpa_build_scan().

◆ unique_nonjoin_rtekind()

static RTEKind unique_nonjoin_rtekind ( Bitmapset relids,
List rtable 
)
static

Definition at line 242 of file pgpa_scan.c.

243{
244 int rti = -1;
245 bool first = true;
246 RTEKind rtekind;
247
248 Assert(relids != NULL);
249
250 while ((rti = bms_next_member(relids, rti)) >= 0)
251 {
252 RangeTblEntry *rte = rt_fetch(rti, rtable);
253
254 if (rte->rtekind == RTE_JOIN)
255 continue;
256
257 if (first)
258 {
259 rtekind = rte->rtekind;
260 first = false;
261 }
262 else if (rtekind != rte->rtekind)
263 elog(ERROR, "rtekind mismatch: %d vs. %d",
264 rtekind, rte->rtekind);
265 }
266
267 if (first)
268 elog(ERROR, "no non-RTE_JOIN RTEs found");
269
270 return rtekind;
271}
int bms_next_member(const Bitmapset *a, int prevbit)
Definition bitmapset.c:1290
#define Assert(condition)
Definition c.h:927
RTEKind
@ RTE_JOIN
#define rt_fetch(rangetable_index, rangetable)
Definition parsetree.h:31

References Assert, bms_next_member(), elog, ERROR, fb(), rt_fetch, and RTE_JOIN.

Referenced by pgpa_build_scan().