1 | /*------------------------------------------------------------------------- |
2 | * |
3 | * placeholder.c |
4 | * PlaceHolderVar and PlaceHolderInfo manipulation routines |
5 | * |
6 | * |
7 | * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group |
8 | * Portions Copyright (c) 1994, Regents of the University of California |
9 | * |
10 | * |
11 | * IDENTIFICATION |
12 | * src/backend/optimizer/util/placeholder.c |
13 | * |
14 | *------------------------------------------------------------------------- |
15 | */ |
16 | #include "postgres.h" |
17 | |
18 | #include "nodes/nodeFuncs.h" |
19 | #include "optimizer/cost.h" |
20 | #include "optimizer/optimizer.h" |
21 | #include "optimizer/pathnode.h" |
22 | #include "optimizer/placeholder.h" |
23 | #include "optimizer/planmain.h" |
24 | #include "utils/lsyscache.h" |
25 | |
26 | /* Local functions */ |
27 | static void find_placeholders_recurse(PlannerInfo *root, Node *jtnode); |
28 | static void find_placeholders_in_expr(PlannerInfo *root, Node *expr); |
29 | |
30 | |
31 | /* |
32 | * make_placeholder_expr |
33 | * Make a PlaceHolderVar for the given expression. |
34 | * |
35 | * phrels is the syntactic location (as a set of baserels) to attribute |
36 | * to the expression. |
37 | */ |
38 | PlaceHolderVar * |
39 | make_placeholder_expr(PlannerInfo *root, Expr *expr, Relids phrels) |
40 | { |
41 | PlaceHolderVar *phv = makeNode(PlaceHolderVar); |
42 | |
43 | phv->phexpr = expr; |
44 | phv->phrels = phrels; |
45 | phv->phid = ++(root->glob->lastPHId); |
46 | phv->phlevelsup = 0; |
47 | |
48 | return phv; |
49 | } |
50 | |
51 | /* |
52 | * find_placeholder_info |
53 | * Fetch the PlaceHolderInfo for the given PHV |
54 | * |
55 | * If the PlaceHolderInfo doesn't exist yet, create it if create_new_ph is |
56 | * true, else throw an error. |
57 | * |
58 | * This is separate from make_placeholder_expr because subquery pullup has |
59 | * to make PlaceHolderVars for expressions that might not be used at all in |
60 | * the upper query, or might not remain after const-expression simplification. |
61 | * We build PlaceHolderInfos only for PHVs that are still present in the |
62 | * simplified query passed to query_planner(). |
63 | * |
64 | * Note: this should only be called after query_planner() has started. Also, |
65 | * create_new_ph must not be true after deconstruct_jointree begins, because |
66 | * make_outerjoininfo assumes that we already know about all placeholders. |
67 | */ |
68 | PlaceHolderInfo * |
69 | find_placeholder_info(PlannerInfo *root, PlaceHolderVar *phv, |
70 | bool create_new_ph) |
71 | { |
72 | PlaceHolderInfo *phinfo; |
73 | Relids rels_used; |
74 | ListCell *lc; |
75 | |
76 | /* if this ever isn't true, we'd need to be able to look in parent lists */ |
77 | Assert(phv->phlevelsup == 0); |
78 | |
79 | foreach(lc, root->placeholder_list) |
80 | { |
81 | phinfo = (PlaceHolderInfo *) lfirst(lc); |
82 | if (phinfo->phid == phv->phid) |
83 | return phinfo; |
84 | } |
85 | |
86 | /* Not found, so create it */ |
87 | if (!create_new_ph) |
88 | elog(ERROR, "too late to create a new PlaceHolderInfo" ); |
89 | |
90 | phinfo = makeNode(PlaceHolderInfo); |
91 | |
92 | phinfo->phid = phv->phid; |
93 | phinfo->ph_var = copyObject(phv); |
94 | |
95 | /* |
96 | * Any referenced rels that are outside the PHV's syntactic scope are |
97 | * LATERAL references, which should be included in ph_lateral but not in |
98 | * ph_eval_at. If no referenced rels are within the syntactic scope, |
99 | * force evaluation at the syntactic location. |
100 | */ |
101 | rels_used = pull_varnos((Node *) phv->phexpr); |
102 | phinfo->ph_lateral = bms_difference(rels_used, phv->phrels); |
103 | if (bms_is_empty(phinfo->ph_lateral)) |
104 | phinfo->ph_lateral = NULL; /* make it exactly NULL if empty */ |
105 | phinfo->ph_eval_at = bms_int_members(rels_used, phv->phrels); |
106 | /* If no contained vars, force evaluation at syntactic location */ |
107 | if (bms_is_empty(phinfo->ph_eval_at)) |
108 | { |
109 | phinfo->ph_eval_at = bms_copy(phv->phrels); |
110 | Assert(!bms_is_empty(phinfo->ph_eval_at)); |
111 | } |
112 | /* ph_eval_at may change later, see update_placeholder_eval_levels */ |
113 | phinfo->ph_needed = NULL; /* initially it's unused */ |
114 | /* for the moment, estimate width using just the datatype info */ |
115 | phinfo->ph_width = get_typavgwidth(exprType((Node *) phv->phexpr), |
116 | exprTypmod((Node *) phv->phexpr)); |
117 | |
118 | root->placeholder_list = lappend(root->placeholder_list, phinfo); |
119 | |
120 | /* |
121 | * The PHV's contained expression may contain other, lower-level PHVs. We |
122 | * now know we need to get those into the PlaceHolderInfo list, too, so we |
123 | * may as well do that immediately. |
124 | */ |
125 | find_placeholders_in_expr(root, (Node *) phinfo->ph_var->phexpr); |
126 | |
127 | return phinfo; |
128 | } |
129 | |
130 | /* |
131 | * find_placeholders_in_jointree |
132 | * Search the jointree for PlaceHolderVars, and build PlaceHolderInfos |
133 | * |
134 | * We don't need to look at the targetlist because build_base_rel_tlists() |
135 | * will already have made entries for any PHVs in the tlist. |
136 | * |
137 | * This is called before we begin deconstruct_jointree. Once we begin |
138 | * deconstruct_jointree, all active placeholders must be present in |
139 | * root->placeholder_list, because make_outerjoininfo and |
140 | * update_placeholder_eval_levels require this info to be available |
141 | * while we crawl up the join tree. |
142 | */ |
143 | void |
144 | find_placeholders_in_jointree(PlannerInfo *root) |
145 | { |
146 | /* We need do nothing if the query contains no PlaceHolderVars */ |
147 | if (root->glob->lastPHId != 0) |
148 | { |
149 | /* Start recursion at top of jointree */ |
150 | Assert(root->parse->jointree != NULL && |
151 | IsA(root->parse->jointree, FromExpr)); |
152 | find_placeholders_recurse(root, (Node *) root->parse->jointree); |
153 | } |
154 | } |
155 | |
156 | /* |
157 | * find_placeholders_recurse |
158 | * One recursion level of find_placeholders_in_jointree. |
159 | * |
160 | * jtnode is the current jointree node to examine. |
161 | */ |
162 | static void |
163 | find_placeholders_recurse(PlannerInfo *root, Node *jtnode) |
164 | { |
165 | if (jtnode == NULL) |
166 | return; |
167 | if (IsA(jtnode, RangeTblRef)) |
168 | { |
169 | /* No quals to deal with here */ |
170 | } |
171 | else if (IsA(jtnode, FromExpr)) |
172 | { |
173 | FromExpr *f = (FromExpr *) jtnode; |
174 | ListCell *l; |
175 | |
176 | /* |
177 | * First, recurse to handle child joins. |
178 | */ |
179 | foreach(l, f->fromlist) |
180 | { |
181 | find_placeholders_recurse(root, lfirst(l)); |
182 | } |
183 | |
184 | /* |
185 | * Now process the top-level quals. |
186 | */ |
187 | find_placeholders_in_expr(root, f->quals); |
188 | } |
189 | else if (IsA(jtnode, JoinExpr)) |
190 | { |
191 | JoinExpr *j = (JoinExpr *) jtnode; |
192 | |
193 | /* |
194 | * First, recurse to handle child joins. |
195 | */ |
196 | find_placeholders_recurse(root, j->larg); |
197 | find_placeholders_recurse(root, j->rarg); |
198 | |
199 | /* Process the qual clauses */ |
200 | find_placeholders_in_expr(root, j->quals); |
201 | } |
202 | else |
203 | elog(ERROR, "unrecognized node type: %d" , |
204 | (int) nodeTag(jtnode)); |
205 | } |
206 | |
207 | /* |
208 | * find_placeholders_in_expr |
209 | * Find all PlaceHolderVars in the given expression, and create |
210 | * PlaceHolderInfo entries for them. |
211 | */ |
212 | static void |
213 | find_placeholders_in_expr(PlannerInfo *root, Node *expr) |
214 | { |
215 | List *vars; |
216 | ListCell *vl; |
217 | |
218 | /* |
219 | * pull_var_clause does more than we need here, but it'll do and it's |
220 | * convenient to use. |
221 | */ |
222 | vars = pull_var_clause(expr, |
223 | PVC_RECURSE_AGGREGATES | |
224 | PVC_RECURSE_WINDOWFUNCS | |
225 | PVC_INCLUDE_PLACEHOLDERS); |
226 | foreach(vl, vars) |
227 | { |
228 | PlaceHolderVar *phv = (PlaceHolderVar *) lfirst(vl); |
229 | |
230 | /* Ignore any plain Vars */ |
231 | if (!IsA(phv, PlaceHolderVar)) |
232 | continue; |
233 | |
234 | /* Create a PlaceHolderInfo entry if there's not one already */ |
235 | (void) find_placeholder_info(root, phv, true); |
236 | } |
237 | list_free(vars); |
238 | } |
239 | |
240 | /* |
241 | * update_placeholder_eval_levels |
242 | * Adjust the target evaluation levels for placeholders |
243 | * |
244 | * The initial eval_at level set by find_placeholder_info was the set of |
245 | * rels used in the placeholder's expression (or the whole subselect below |
246 | * the placeholder's syntactic location, if the expr is variable-free). |
247 | * If the query contains any outer joins that can null any of those rels, |
248 | * we must delay evaluation to above those joins. |
249 | * |
250 | * We repeat this operation each time we add another outer join to |
251 | * root->join_info_list. It's somewhat annoying to have to do that, but |
252 | * since we don't have very much information on the placeholders' locations, |
253 | * it's hard to avoid. Each placeholder's eval_at level must be correct |
254 | * by the time it starts to figure in outer-join delay decisions for higher |
255 | * outer joins. |
256 | * |
257 | * In future we might want to put additional policy/heuristics here to |
258 | * try to determine an optimal evaluation level. The current rules will |
259 | * result in evaluation at the lowest possible level. However, pushing a |
260 | * placeholder eval up the tree is likely to further constrain evaluation |
261 | * order for outer joins, so it could easily be counterproductive; and we |
262 | * don't have enough information at this point to make an intelligent choice. |
263 | */ |
264 | void |
265 | update_placeholder_eval_levels(PlannerInfo *root, SpecialJoinInfo *new_sjinfo) |
266 | { |
267 | ListCell *lc1; |
268 | |
269 | foreach(lc1, root->placeholder_list) |
270 | { |
271 | PlaceHolderInfo *phinfo = (PlaceHolderInfo *) lfirst(lc1); |
272 | Relids syn_level = phinfo->ph_var->phrels; |
273 | Relids eval_at; |
274 | bool found_some; |
275 | ListCell *lc2; |
276 | |
277 | /* |
278 | * We don't need to do any work on this placeholder unless the |
279 | * newly-added outer join is syntactically beneath its location. |
280 | */ |
281 | if (!bms_is_subset(new_sjinfo->syn_lefthand, syn_level) || |
282 | !bms_is_subset(new_sjinfo->syn_righthand, syn_level)) |
283 | continue; |
284 | |
285 | /* |
286 | * Check for delays due to lower outer joins. This is the same logic |
287 | * as in check_outerjoin_delay in initsplan.c, except that we don't |
288 | * have anything to do with the delay_upper_joins flags; delay of |
289 | * upper outer joins will be handled later, based on the eval_at |
290 | * values we compute now. |
291 | */ |
292 | eval_at = phinfo->ph_eval_at; |
293 | |
294 | do |
295 | { |
296 | found_some = false; |
297 | foreach(lc2, root->join_info_list) |
298 | { |
299 | SpecialJoinInfo *sjinfo = (SpecialJoinInfo *) lfirst(lc2); |
300 | |
301 | /* disregard joins not within the PHV's sub-select */ |
302 | if (!bms_is_subset(sjinfo->syn_lefthand, syn_level) || |
303 | !bms_is_subset(sjinfo->syn_righthand, syn_level)) |
304 | continue; |
305 | |
306 | /* do we reference any nullable rels of this OJ? */ |
307 | if (bms_overlap(eval_at, sjinfo->min_righthand) || |
308 | (sjinfo->jointype == JOIN_FULL && |
309 | bms_overlap(eval_at, sjinfo->min_lefthand))) |
310 | { |
311 | /* yes; have we included all its rels in eval_at? */ |
312 | if (!bms_is_subset(sjinfo->min_lefthand, eval_at) || |
313 | !bms_is_subset(sjinfo->min_righthand, eval_at)) |
314 | { |
315 | /* no, so add them in */ |
316 | eval_at = bms_add_members(eval_at, |
317 | sjinfo->min_lefthand); |
318 | eval_at = bms_add_members(eval_at, |
319 | sjinfo->min_righthand); |
320 | /* we'll need another iteration */ |
321 | found_some = true; |
322 | } |
323 | } |
324 | } |
325 | } while (found_some); |
326 | |
327 | /* Can't move the PHV's eval_at level to above its syntactic level */ |
328 | Assert(bms_is_subset(eval_at, syn_level)); |
329 | |
330 | phinfo->ph_eval_at = eval_at; |
331 | } |
332 | } |
333 | |
334 | /* |
335 | * fix_placeholder_input_needed_levels |
336 | * Adjust the "needed at" levels for placeholder inputs |
337 | * |
338 | * This is called after we've finished determining the eval_at levels for |
339 | * all placeholders. We need to make sure that all vars and placeholders |
340 | * needed to evaluate each placeholder will be available at the scan or join |
341 | * level where the evaluation will be done. (It might seem that scan-level |
342 | * evaluations aren't interesting, but that's not so: a LATERAL reference |
343 | * within a placeholder's expression needs to cause the referenced var or |
344 | * placeholder to be marked as needed in the scan where it's evaluated.) |
345 | * Note that this loop can have side-effects on the ph_needed sets of other |
346 | * PlaceHolderInfos; that's okay because we don't examine ph_needed here, so |
347 | * there are no ordering issues to worry about. |
348 | */ |
349 | void |
350 | fix_placeholder_input_needed_levels(PlannerInfo *root) |
351 | { |
352 | ListCell *lc; |
353 | |
354 | foreach(lc, root->placeholder_list) |
355 | { |
356 | PlaceHolderInfo *phinfo = (PlaceHolderInfo *) lfirst(lc); |
357 | List *vars = pull_var_clause((Node *) phinfo->ph_var->phexpr, |
358 | PVC_RECURSE_AGGREGATES | |
359 | PVC_RECURSE_WINDOWFUNCS | |
360 | PVC_INCLUDE_PLACEHOLDERS); |
361 | |
362 | add_vars_to_targetlist(root, vars, phinfo->ph_eval_at, false); |
363 | list_free(vars); |
364 | } |
365 | } |
366 | |
367 | /* |
368 | * add_placeholders_to_base_rels |
369 | * Add any required PlaceHolderVars to base rels' targetlists. |
370 | * |
371 | * If any placeholder can be computed at a base rel and is needed above it, |
372 | * add it to that rel's targetlist. This might look like it could be merged |
373 | * with fix_placeholder_input_needed_levels, but it must be separate because |
374 | * join removal happens in between, and can change the ph_eval_at sets. There |
375 | * is essentially the same logic in add_placeholders_to_joinrel, but we can't |
376 | * do that part until joinrels are formed. |
377 | */ |
378 | void |
379 | add_placeholders_to_base_rels(PlannerInfo *root) |
380 | { |
381 | ListCell *lc; |
382 | |
383 | foreach(lc, root->placeholder_list) |
384 | { |
385 | PlaceHolderInfo *phinfo = (PlaceHolderInfo *) lfirst(lc); |
386 | Relids eval_at = phinfo->ph_eval_at; |
387 | int varno; |
388 | |
389 | if (bms_get_singleton_member(eval_at, &varno) && |
390 | bms_nonempty_difference(phinfo->ph_needed, eval_at)) |
391 | { |
392 | RelOptInfo *rel = find_base_rel(root, varno); |
393 | |
394 | rel->reltarget->exprs = lappend(rel->reltarget->exprs, |
395 | copyObject(phinfo->ph_var)); |
396 | /* reltarget's cost and width fields will be updated later */ |
397 | } |
398 | } |
399 | } |
400 | |
401 | /* |
402 | * add_placeholders_to_joinrel |
403 | * Add any required PlaceHolderVars to a join rel's targetlist; |
404 | * and if they contain lateral references, add those references to the |
405 | * joinrel's direct_lateral_relids. |
406 | * |
407 | * A join rel should emit a PlaceHolderVar if (a) the PHV is needed above |
408 | * this join level and (b) the PHV can be computed at or below this level. |
409 | */ |
410 | void |
411 | add_placeholders_to_joinrel(PlannerInfo *root, RelOptInfo *joinrel, |
412 | RelOptInfo *outer_rel, RelOptInfo *inner_rel) |
413 | { |
414 | Relids relids = joinrel->relids; |
415 | ListCell *lc; |
416 | |
417 | foreach(lc, root->placeholder_list) |
418 | { |
419 | PlaceHolderInfo *phinfo = (PlaceHolderInfo *) lfirst(lc); |
420 | |
421 | /* Is it still needed above this joinrel? */ |
422 | if (bms_nonempty_difference(phinfo->ph_needed, relids)) |
423 | { |
424 | /* Is it computable here? */ |
425 | if (bms_is_subset(phinfo->ph_eval_at, relids)) |
426 | { |
427 | /* Yup, add it to the output */ |
428 | joinrel->reltarget->exprs = lappend(joinrel->reltarget->exprs, |
429 | phinfo->ph_var); |
430 | joinrel->reltarget->width += phinfo->ph_width; |
431 | |
432 | /* |
433 | * Charge the cost of evaluating the contained expression if |
434 | * the PHV can be computed here but not in either input. This |
435 | * is a bit bogus because we make the decision based on the |
436 | * first pair of possible input relations considered for the |
437 | * joinrel. With other pairs, it might be possible to compute |
438 | * the PHV in one input or the other, and then we'd be double |
439 | * charging the PHV's cost for some join paths. For now, live |
440 | * with that; but we might want to improve it later by |
441 | * refiguring the reltarget costs for each pair of inputs. |
442 | */ |
443 | if (!bms_is_subset(phinfo->ph_eval_at, outer_rel->relids) && |
444 | !bms_is_subset(phinfo->ph_eval_at, inner_rel->relids)) |
445 | { |
446 | QualCost cost; |
447 | |
448 | cost_qual_eval_node(&cost, (Node *) phinfo->ph_var->phexpr, |
449 | root); |
450 | joinrel->reltarget->cost.startup += cost.startup; |
451 | joinrel->reltarget->cost.per_tuple += cost.per_tuple; |
452 | } |
453 | |
454 | /* Adjust joinrel's direct_lateral_relids as needed */ |
455 | joinrel->direct_lateral_relids = |
456 | bms_add_members(joinrel->direct_lateral_relids, |
457 | phinfo->ph_lateral); |
458 | } |
459 | } |
460 | } |
461 | } |
462 | |