/Users/deen/code/yugabyte-db/src/postgres/src/backend/optimizer/util/paramassign.c
Line | Count | Source (jump to first uncovered line) |
1 | | /*------------------------------------------------------------------------- |
2 | | * |
3 | | * paramassign.c |
4 | | * Functions for assigning PARAM_EXEC slots during planning. |
5 | | * |
6 | | * This module is responsible for managing three planner data structures: |
7 | | * |
8 | | * root->glob->paramExecTypes: records actual assignments of PARAM_EXEC slots. |
9 | | * The i'th list element holds the data type OID of the i'th parameter slot. |
10 | | * (Elements can be InvalidOid if they represent slots that are needed for |
11 | | * chgParam signaling, but will never hold a value at runtime.) This list is |
12 | | * global to the whole plan since the executor has only one PARAM_EXEC array. |
13 | | * Assignments are permanent for the plan: we never remove entries once added. |
14 | | * |
15 | | * root->plan_params: a list of PlannerParamItem nodes, recording Vars and |
16 | | * PlaceHolderVars that the root's query level needs to supply to lower-level |
17 | | * subqueries, along with the PARAM_EXEC number to use for each such value. |
18 | | * Elements are added to this list while planning a subquery, and the list |
19 | | * is reset to empty after completion of each subquery. |
20 | | * |
21 | | * root->curOuterParams: a list of NestLoopParam nodes, recording Vars and |
22 | | * PlaceHolderVars that some outer level of nestloop needs to pass down to |
23 | | * a lower-level plan node in its righthand side. Elements are added to this |
24 | | * list as createplan.c creates lower Plan nodes that need such Params, and |
25 | | * are removed when it creates a NestLoop Plan node that will supply those |
26 | | * values. |
27 | | * |
28 | | * The latter two data structures are used to prevent creating multiple |
29 | | * PARAM_EXEC slots (each requiring work to fill) when the same upper |
30 | | * SubPlan or NestLoop supplies a value that is referenced in more than |
31 | | * one place in its child plan nodes. However, when the same Var has to |
32 | | * be supplied to different subplan trees by different SubPlan or NestLoop |
33 | | * parent nodes, we don't recognize any commonality; a fresh plan_params or |
34 | | * curOuterParams entry will be made (since the old one has been removed |
35 | | * when we finished processing the earlier SubPlan or NestLoop) and a fresh |
36 | | * PARAM_EXEC number will be assigned. At one time we tried to avoid |
37 | | * allocating duplicate PARAM_EXEC numbers in such cases, but it's harder |
38 | | * than it seems to avoid bugs due to overlapping Param lifetimes, so we |
39 | | * don't risk that anymore. Minimizing the number of PARAM_EXEC slots |
40 | | * doesn't really save much executor work anyway. |
41 | | * |
42 | | * |
43 | | * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group |
44 | | * Portions Copyright (c) 1994, Regents of the University of California |
45 | | * |
46 | | * IDENTIFICATION |
47 | | * src/backend/optimizer/util/paramassign.c |
48 | | * |
49 | | *------------------------------------------------------------------------- |
50 | | */ |
51 | | #include "postgres.h" |
52 | | |
53 | | #include "nodes/nodeFuncs.h" |
54 | | #include "nodes/plannodes.h" |
55 | | #include "optimizer/paramassign.h" |
56 | | #include "optimizer/placeholder.h" |
57 | | #include "rewrite/rewriteManip.h" |
58 | | |
59 | | |
60 | | /* |
61 | | * Select a PARAM_EXEC number to identify the given Var as a parameter for |
62 | | * the current subquery. (It might already have one.) |
63 | | * Record the need for the Var in the proper upper-level root->plan_params. |
64 | | */ |
65 | | static int |
66 | | assign_param_for_var(PlannerInfo *root, Var *var) |
67 | 1.52k | { |
68 | 1.52k | ListCell *ppl; |
69 | 1.52k | PlannerParamItem *pitem; |
70 | 1.52k | Index levelsup; |
71 | | |
72 | | /* Find the query level the Var belongs to */ |
73 | 3.04k | for (levelsup = var->varlevelsup; levelsup > 0; levelsup--) |
74 | 1.52k | root = root->parent_root; |
75 | | |
76 | | /* If there's already a matching PlannerParamItem there, just use it */ |
77 | 1.52k | foreach(ppl, root->plan_params) |
78 | 265 | { |
79 | 265 | pitem = (PlannerParamItem *) lfirst(ppl); |
80 | 265 | if (IsA(pitem->item, Var)) |
81 | 265 | { |
82 | 265 | Var *pvar = (Var *) pitem->item; |
83 | | |
84 | | /* |
85 | | * This comparison must match _equalVar(), except for ignoring |
86 | | * varlevelsup. Note that _equalVar() ignores the location. |
87 | | */ |
88 | 265 | if (pvar->varno == var->varno && |
89 | 223 | pvar->varattno == var->varattno && |
90 | 30 | pvar->vartype == var->vartype && |
91 | 30 | pvar->vartypmod == var->vartypmod && |
92 | 30 | pvar->varcollid == var->varcollid && |
93 | 30 | pvar->varnoold == var->varnoold && |
94 | 30 | pvar->varoattno == var->varoattno) |
95 | 30 | return pitem->paramId; |
96 | 265 | } |
97 | 265 | } |
98 | | |
99 | | /* Nope, so make a new one */ |
100 | 1.49k | var = copyObject(var); |
101 | 1.49k | var->varlevelsup = 0; |
102 | | |
103 | 1.49k | pitem = makeNode(PlannerParamItem); |
104 | 1.49k | pitem->item = (Node *) var; |
105 | 1.49k | pitem->paramId = list_length(root->glob->paramExecTypes); |
106 | 1.49k | root->glob->paramExecTypes = lappend_oid(root->glob->paramExecTypes, |
107 | 1.49k | var->vartype); |
108 | | |
109 | 1.49k | root->plan_params = lappend(root->plan_params, pitem); |
110 | | |
111 | 1.49k | return pitem->paramId; |
112 | 1.52k | } |
113 | | |
114 | | /* |
115 | | * Generate a Param node to replace the given Var, |
116 | | * which is expected to have varlevelsup > 0 (ie, it is not local). |
117 | | * Record the need for the Var in the proper upper-level root->plan_params. |
118 | | */ |
119 | | Param * |
120 | | replace_outer_var(PlannerInfo *root, Var *var) |
121 | 1.52k | { |
122 | 1.52k | Param *retval; |
123 | 1.52k | int i; |
124 | | |
125 | 1.52k | Assert(var->varlevelsup > 0 && var->varlevelsup < root->query_level); |
126 | | |
127 | | /* Find the Var in the appropriate plan_params, or add it if not present */ |
128 | 1.52k | i = assign_param_for_var(root, var); |
129 | | |
130 | 1.52k | retval = makeNode(Param); |
131 | 1.52k | retval->paramkind = PARAM_EXEC; |
132 | 1.52k | retval->paramid = i; |
133 | 1.52k | retval->paramtype = var->vartype; |
134 | 1.52k | retval->paramtypmod = var->vartypmod; |
135 | 1.52k | retval->paramcollid = var->varcollid; |
136 | 1.52k | retval->location = var->location; |
137 | | |
138 | 1.52k | return retval; |
139 | 1.52k | } |
140 | | |
141 | | /* |
142 | | * Select a PARAM_EXEC number to identify the given PlaceHolderVar as a |
143 | | * parameter for the current subquery. (It might already have one.) |
144 | | * Record the need for the PHV in the proper upper-level root->plan_params. |
145 | | * |
146 | | * This is just like assign_param_for_var, except for PlaceHolderVars. |
147 | | */ |
148 | | static int |
149 | | assign_param_for_placeholdervar(PlannerInfo *root, PlaceHolderVar *phv) |
150 | 0 | { |
151 | 0 | ListCell *ppl; |
152 | 0 | PlannerParamItem *pitem; |
153 | 0 | Index levelsup; |
154 | | |
155 | | /* Find the query level the PHV belongs to */ |
156 | 0 | for (levelsup = phv->phlevelsup; levelsup > 0; levelsup--) |
157 | 0 | root = root->parent_root; |
158 | | |
159 | | /* If there's already a matching PlannerParamItem there, just use it */ |
160 | 0 | foreach(ppl, root->plan_params) |
161 | 0 | { |
162 | 0 | pitem = (PlannerParamItem *) lfirst(ppl); |
163 | 0 | if (IsA(pitem->item, PlaceHolderVar)) |
164 | 0 | { |
165 | 0 | PlaceHolderVar *pphv = (PlaceHolderVar *) pitem->item; |
166 | | |
167 | | /* We assume comparing the PHIDs is sufficient */ |
168 | 0 | if (pphv->phid == phv->phid) |
169 | 0 | return pitem->paramId; |
170 | 0 | } |
171 | 0 | } |
172 | | |
173 | | /* Nope, so make a new one */ |
174 | 0 | phv = copyObject(phv); |
175 | 0 | IncrementVarSublevelsUp((Node *) phv, -((int) phv->phlevelsup), 0); |
176 | 0 | Assert(phv->phlevelsup == 0); |
177 | |
|
178 | 0 | pitem = makeNode(PlannerParamItem); |
179 | 0 | pitem->item = (Node *) phv; |
180 | 0 | pitem->paramId = list_length(root->glob->paramExecTypes); |
181 | 0 | root->glob->paramExecTypes = lappend_oid(root->glob->paramExecTypes, |
182 | 0 | exprType((Node *) phv->phexpr)); |
183 | |
|
184 | 0 | root->plan_params = lappend(root->plan_params, pitem); |
185 | |
|
186 | 0 | return pitem->paramId; |
187 | 0 | } |
188 | | |
189 | | /* |
190 | | * Generate a Param node to replace the given PlaceHolderVar, |
191 | | * which is expected to have phlevelsup > 0 (ie, it is not local). |
192 | | * Record the need for the PHV in the proper upper-level root->plan_params. |
193 | | * |
194 | | * This is just like replace_outer_var, except for PlaceHolderVars. |
195 | | */ |
196 | | Param * |
197 | | replace_outer_placeholdervar(PlannerInfo *root, PlaceHolderVar *phv) |
198 | 0 | { |
199 | 0 | Param *retval; |
200 | 0 | int i; |
201 | |
|
202 | 0 | Assert(phv->phlevelsup > 0 && phv->phlevelsup < root->query_level); |
203 | | |
204 | | /* Find the PHV in the appropriate plan_params, or add it if not present */ |
205 | 0 | i = assign_param_for_placeholdervar(root, phv); |
206 | |
|
207 | 0 | retval = makeNode(Param); |
208 | 0 | retval->paramkind = PARAM_EXEC; |
209 | 0 | retval->paramid = i; |
210 | 0 | retval->paramtype = exprType((Node *) phv->phexpr); |
211 | 0 | retval->paramtypmod = exprTypmod((Node *) phv->phexpr); |
212 | 0 | retval->paramcollid = exprCollation((Node *) phv->phexpr); |
213 | 0 | retval->location = -1; |
214 | |
|
215 | 0 | return retval; |
216 | 0 | } |
217 | | |
218 | | /* |
219 | | * Generate a Param node to replace the given Aggref |
220 | | * which is expected to have agglevelsup > 0 (ie, it is not local). |
221 | | * Record the need for the Aggref in the proper upper-level root->plan_params. |
222 | | */ |
223 | | Param * |
224 | | replace_outer_agg(PlannerInfo *root, Aggref *agg) |
225 | 7 | { |
226 | 7 | Param *retval; |
227 | 7 | PlannerParamItem *pitem; |
228 | 7 | Index levelsup; |
229 | | |
230 | 7 | Assert(agg->agglevelsup > 0 && agg->agglevelsup < root->query_level); |
231 | | |
232 | | /* Find the query level the Aggref belongs to */ |
233 | 14 | for (levelsup = agg->agglevelsup; levelsup > 0; levelsup--) |
234 | 7 | root = root->parent_root; |
235 | | |
236 | | /* |
237 | | * It does not seem worthwhile to try to de-duplicate references to outer |
238 | | * aggs. Just make a new slot every time. |
239 | | */ |
240 | 7 | agg = copyObject(agg); |
241 | 7 | IncrementVarSublevelsUp((Node *) agg, -((int) agg->agglevelsup), 0); |
242 | 7 | Assert(agg->agglevelsup == 0); |
243 | | |
244 | 7 | pitem = makeNode(PlannerParamItem); |
245 | 7 | pitem->item = (Node *) agg; |
246 | 7 | pitem->paramId = list_length(root->glob->paramExecTypes); |
247 | 7 | root->glob->paramExecTypes = lappend_oid(root->glob->paramExecTypes, |
248 | 7 | agg->aggtype); |
249 | | |
250 | 7 | root->plan_params = lappend(root->plan_params, pitem); |
251 | | |
252 | 7 | retval = makeNode(Param); |
253 | 7 | retval->paramkind = PARAM_EXEC; |
254 | 7 | retval->paramid = pitem->paramId; |
255 | 7 | retval->paramtype = agg->aggtype; |
256 | 7 | retval->paramtypmod = -1; |
257 | 7 | retval->paramcollid = agg->aggcollid; |
258 | 7 | retval->location = agg->location; |
259 | | |
260 | 7 | return retval; |
261 | 7 | } |
262 | | |
263 | | /* |
264 | | * Generate a Param node to replace the given GroupingFunc expression which is |
265 | | * expected to have agglevelsup > 0 (ie, it is not local). |
266 | | * Record the need for the GroupingFunc in the proper upper-level |
267 | | * root->plan_params. |
268 | | */ |
269 | | Param * |
270 | | replace_outer_grouping(PlannerInfo *root, GroupingFunc *grp) |
271 | 0 | { |
272 | 0 | Param *retval; |
273 | 0 | PlannerParamItem *pitem; |
274 | 0 | Index levelsup; |
275 | 0 | Oid ptype = exprType((Node *) grp); |
276 | |
|
277 | 0 | Assert(grp->agglevelsup > 0 && grp->agglevelsup < root->query_level); |
278 | | |
279 | | /* Find the query level the GroupingFunc belongs to */ |
280 | 0 | for (levelsup = grp->agglevelsup; levelsup > 0; levelsup--) |
281 | 0 | root = root->parent_root; |
282 | | |
283 | | /* |
284 | | * It does not seem worthwhile to try to de-duplicate references to outer |
285 | | * aggs. Just make a new slot every time. |
286 | | */ |
287 | 0 | grp = copyObject(grp); |
288 | 0 | IncrementVarSublevelsUp((Node *) grp, -((int) grp->agglevelsup), 0); |
289 | 0 | Assert(grp->agglevelsup == 0); |
290 | |
|
291 | 0 | pitem = makeNode(PlannerParamItem); |
292 | 0 | pitem->item = (Node *) grp; |
293 | 0 | pitem->paramId = list_length(root->glob->paramExecTypes); |
294 | 0 | root->glob->paramExecTypes = lappend_oid(root->glob->paramExecTypes, |
295 | 0 | ptype); |
296 | |
|
297 | 0 | root->plan_params = lappend(root->plan_params, pitem); |
298 | |
|
299 | 0 | retval = makeNode(Param); |
300 | 0 | retval->paramkind = PARAM_EXEC; |
301 | 0 | retval->paramid = pitem->paramId; |
302 | 0 | retval->paramtype = ptype; |
303 | 0 | retval->paramtypmod = -1; |
304 | 0 | retval->paramcollid = InvalidOid; |
305 | 0 | retval->location = grp->location; |
306 | |
|
307 | 0 | return retval; |
308 | 0 | } |
309 | | |
310 | | /* |
311 | | * Generate a Param node to replace the given Var, |
312 | | * which is expected to come from some upper NestLoop plan node. |
313 | | * Record the need for the Var in root->curOuterParams. |
314 | | */ |
315 | | Param * |
316 | | replace_nestloop_param_var(PlannerInfo *root, Var *var) |
317 | 8.31k | { |
318 | 8.31k | Param *param; |
319 | 8.31k | NestLoopParam *nlp; |
320 | 8.31k | ListCell *lc; |
321 | | |
322 | | /* Is this Var already listed in root->curOuterParams? */ |
323 | 8.31k | foreach(lc, root->curOuterParams) |
324 | 4.35k | { |
325 | 4.35k | nlp = (NestLoopParam *) lfirst(lc); |
326 | 4.35k | if (equal(var, nlp->paramval)) |
327 | 4.12k | { |
328 | | /* Yes, so just make a Param referencing this NLP's slot */ |
329 | 4.12k | param = makeNode(Param); |
330 | 4.12k | param->paramkind = PARAM_EXEC; |
331 | 4.12k | param->paramid = nlp->paramno; |
332 | 4.12k | param->paramtype = var->vartype; |
333 | 4.12k | param->paramtypmod = var->vartypmod; |
334 | 4.12k | param->paramcollid = var->varcollid; |
335 | 4.12k | param->location = var->location; |
336 | 4.12k | return param; |
337 | 4.12k | } |
338 | 4.35k | } |
339 | | |
340 | | /* No, so assign a PARAM_EXEC slot for a new NLP */ |
341 | 4.18k | param = generate_new_exec_param(root, |
342 | 4.18k | var->vartype, |
343 | 4.18k | var->vartypmod, |
344 | 4.18k | var->varcollid); |
345 | 4.18k | param->location = var->location; |
346 | | |
347 | | /* Add it to the list of required NLPs */ |
348 | 4.18k | nlp = makeNode(NestLoopParam); |
349 | 4.18k | nlp->paramno = param->paramid; |
350 | 4.18k | nlp->paramval = copyObject(var); |
351 | 4.18k | root->curOuterParams = lappend(root->curOuterParams, nlp); |
352 | | |
353 | | /* And return the replacement Param */ |
354 | 4.18k | return param; |
355 | 8.31k | } |
356 | | |
357 | | /* |
358 | | * Generate a Param node to replace the given PlaceHolderVar, |
359 | | * which is expected to come from some upper NestLoop plan node. |
360 | | * Record the need for the PHV in root->curOuterParams. |
361 | | * |
362 | | * This is just like replace_nestloop_param_var, except for PlaceHolderVars. |
363 | | */ |
364 | | Param * |
365 | | replace_nestloop_param_placeholdervar(PlannerInfo *root, PlaceHolderVar *phv) |
366 | 0 | { |
367 | 0 | Param *param; |
368 | 0 | NestLoopParam *nlp; |
369 | 0 | ListCell *lc; |
370 | | |
371 | | /* Is this PHV already listed in root->curOuterParams? */ |
372 | 0 | foreach(lc, root->curOuterParams) |
373 | 0 | { |
374 | 0 | nlp = (NestLoopParam *) lfirst(lc); |
375 | 0 | if (equal(phv, nlp->paramval)) |
376 | 0 | { |
377 | | /* Yes, so just make a Param referencing this NLP's slot */ |
378 | 0 | param = makeNode(Param); |
379 | 0 | param->paramkind = PARAM_EXEC; |
380 | 0 | param->paramid = nlp->paramno; |
381 | 0 | param->paramtype = exprType((Node *) phv->phexpr); |
382 | 0 | param->paramtypmod = exprTypmod((Node *) phv->phexpr); |
383 | 0 | param->paramcollid = exprCollation((Node *) phv->phexpr); |
384 | 0 | param->location = -1; |
385 | 0 | return param; |
386 | 0 | } |
387 | 0 | } |
388 | | |
389 | | /* No, so assign a PARAM_EXEC slot for a new NLP */ |
390 | 0 | param = generate_new_exec_param(root, |
391 | 0 | exprType((Node *) phv->phexpr), |
392 | 0 | exprTypmod((Node *) phv->phexpr), |
393 | 0 | exprCollation((Node *) phv->phexpr)); |
394 | | |
395 | | /* Add it to the list of required NLPs */ |
396 | 0 | nlp = makeNode(NestLoopParam); |
397 | 0 | nlp->paramno = param->paramid; |
398 | 0 | nlp->paramval = (Var *) copyObject(phv); |
399 | 0 | root->curOuterParams = lappend(root->curOuterParams, nlp); |
400 | | |
401 | | /* And return the replacement Param */ |
402 | 0 | return param; |
403 | 0 | } |
404 | | |
405 | | /* |
406 | | * process_subquery_nestloop_params |
407 | | * Handle params of a parameterized subquery that need to be fed |
408 | | * from an outer nestloop. |
409 | | * |
410 | | * Currently, that would be *all* params that a subquery in FROM has demanded |
411 | | * from the current query level, since they must be LATERAL references. |
412 | | * |
413 | | * subplan_params is a list of PlannerParamItems that we intend to pass to |
414 | | * a subquery-in-FROM. (This was constructed in root->plan_params while |
415 | | * planning the subquery, but isn't there anymore when this is called.) |
416 | | * |
417 | | * The subplan's references to the outer variables are already represented |
418 | | * as PARAM_EXEC Params, since that conversion was done by the routines above |
419 | | * while planning the subquery. So we need not modify the subplan or the |
420 | | * PlannerParamItems here. What we do need to do is add entries to |
421 | | * root->curOuterParams to signal the parent nestloop plan node that it must |
422 | | * provide these values. This differs from replace_nestloop_param_var in |
423 | | * that the PARAM_EXEC slots to use have already been determined. |
424 | | * |
425 | | * Note that we also use root->curOuterRels as an implicit parameter for |
426 | | * sanity checks. |
427 | | */ |
428 | | void |
429 | | process_subquery_nestloop_params(PlannerInfo *root, List *subplan_params) |
430 | 4 | { |
431 | 4 | ListCell *lc; |
432 | | |
433 | 4 | foreach(lc, subplan_params) |
434 | 4 | { |
435 | 4 | PlannerParamItem *pitem = castNode(PlannerParamItem, lfirst(lc)); |
436 | | |
437 | 4 | if (IsA(pitem->item, Var)) |
438 | 4 | { |
439 | 4 | Var *var = (Var *) pitem->item; |
440 | 4 | NestLoopParam *nlp; |
441 | 4 | ListCell *lc; |
442 | | |
443 | | /* If not from a nestloop outer rel, complain */ |
444 | 4 | if (!bms_is_member(var->varno, root->curOuterRels)) |
445 | 0 | elog(ERROR, "non-LATERAL parameter required by subquery"); |
446 | | |
447 | | /* Is this param already listed in root->curOuterParams? */ |
448 | 4 | foreach(lc, root->curOuterParams) |
449 | 1 | { |
450 | 1 | nlp = (NestLoopParam *) lfirst(lc); |
451 | 1 | if (nlp->paramno == pitem->paramId) |
452 | 0 | { |
453 | 0 | Assert(equal(var, nlp->paramval)); |
454 | | /* Present, so nothing to do */ |
455 | 0 | break; |
456 | 0 | } |
457 | 1 | } |
458 | 4 | if (lc == NULL) |
459 | 4 | { |
460 | | /* No, so add it */ |
461 | 4 | nlp = makeNode(NestLoopParam); |
462 | 4 | nlp->paramno = pitem->paramId; |
463 | 4 | nlp->paramval = copyObject(var); |
464 | 4 | root->curOuterParams = lappend(root->curOuterParams, nlp); |
465 | 4 | } |
466 | 4 | } |
467 | 0 | else if (IsA(pitem->item, PlaceHolderVar)) |
468 | 0 | { |
469 | 0 | PlaceHolderVar *phv = (PlaceHolderVar *) pitem->item; |
470 | 0 | NestLoopParam *nlp; |
471 | 0 | ListCell *lc; |
472 | | |
473 | | /* If not from a nestloop outer rel, complain */ |
474 | 0 | if (!bms_is_subset(find_placeholder_info(root, phv, false)->ph_eval_at, |
475 | 0 | root->curOuterRels)) |
476 | 0 | elog(ERROR, "non-LATERAL parameter required by subquery"); |
477 | | |
478 | | /* Is this param already listed in root->curOuterParams? */ |
479 | 0 | foreach(lc, root->curOuterParams) |
480 | 0 | { |
481 | 0 | nlp = (NestLoopParam *) lfirst(lc); |
482 | 0 | if (nlp->paramno == pitem->paramId) |
483 | 0 | { |
484 | 0 | Assert(equal(phv, nlp->paramval)); |
485 | | /* Present, so nothing to do */ |
486 | 0 | break; |
487 | 0 | } |
488 | 0 | } |
489 | 0 | if (lc == NULL) |
490 | 0 | { |
491 | | /* No, so add it */ |
492 | 0 | nlp = makeNode(NestLoopParam); |
493 | 0 | nlp->paramno = pitem->paramId; |
494 | 0 | nlp->paramval = (Var *) copyObject(phv); |
495 | 0 | root->curOuterParams = lappend(root->curOuterParams, nlp); |
496 | 0 | } |
497 | 0 | } |
498 | 0 | else |
499 | 0 | elog(ERROR, "unexpected type of subquery parameter"); |
500 | 4 | } |
501 | 4 | } |
502 | | |
503 | | /* |
504 | | * Identify any NestLoopParams that should be supplied by a NestLoop plan |
505 | | * node with the specified lefthand rels. Remove them from the active |
506 | | * root->curOuterParams list and return them as the result list. |
507 | | */ |
508 | | List * |
509 | | identify_current_nestloop_params(PlannerInfo *root, Relids leftrelids) |
510 | 4.32k | { |
511 | 4.32k | List *result; |
512 | 4.32k | ListCell *cell; |
513 | 4.32k | ListCell *prev; |
514 | 4.32k | ListCell *next; |
515 | | |
516 | 4.32k | result = NIL; |
517 | 4.32k | prev = NULL; |
518 | 8.55k | for (cell = list_head(root->curOuterParams); cell; cell = next) |
519 | 4.23k | { |
520 | 4.23k | NestLoopParam *nlp = (NestLoopParam *) lfirst(cell); |
521 | | |
522 | 4.23k | next = lnext(cell); |
523 | | |
524 | | /* |
525 | | * We are looking for Vars and PHVs that can be supplied by the |
526 | | * lefthand rels. The "bms_overlap" test is just an optimization to |
527 | | * allow skipping find_placeholder_info() if the PHV couldn't match. |
528 | | */ |
529 | 4.23k | if (IsA(nlp->paramval, Var) && |
530 | 4.23k | bms_is_member(nlp->paramval->varno, leftrelids)) |
531 | 4.18k | { |
532 | 4.18k | root->curOuterParams = list_delete_cell(root->curOuterParams, |
533 | 4.18k | cell, prev); |
534 | 4.18k | result = lappend(result, nlp); |
535 | 4.18k | } |
536 | 45 | else if (IsA(nlp->paramval, PlaceHolderVar) && |
537 | 0 | bms_overlap(((PlaceHolderVar *) nlp->paramval)->phrels, |
538 | 0 | leftrelids) && |
539 | 0 | bms_is_subset(find_placeholder_info(root, |
540 | 0 | (PlaceHolderVar *) nlp->paramval, |
541 | 0 | false)->ph_eval_at, |
542 | 0 | leftrelids)) |
543 | 0 | { |
544 | 0 | root->curOuterParams = list_delete_cell(root->curOuterParams, |
545 | 0 | cell, prev); |
546 | 0 | result = lappend(result, nlp); |
547 | 0 | } |
548 | 45 | else |
549 | 45 | prev = cell; |
550 | 4.23k | } |
551 | 4.32k | return result; |
552 | 4.32k | } |
553 | | |
554 | | /* |
555 | | * Generate a new Param node that will not conflict with any other. |
556 | | * |
557 | | * This is used to create Params representing subplan outputs or |
558 | | * NestLoop parameters. |
559 | | * |
560 | | * We don't need to build a PlannerParamItem for such a Param, but we do |
561 | | * need to make sure we record the type in paramExecTypes (otherwise, |
562 | | * there won't be a slot allocated for it). |
563 | | */ |
564 | | Param * |
565 | | generate_new_exec_param(PlannerInfo *root, Oid paramtype, int32 paramtypmod, |
566 | | Oid paramcollation) |
567 | 11.6k | { |
568 | 11.6k | Param *retval; |
569 | | |
570 | 11.6k | retval = makeNode(Param); |
571 | 11.6k | retval->paramkind = PARAM_EXEC; |
572 | 11.6k | retval->paramid = list_length(root->glob->paramExecTypes); |
573 | 11.6k | root->glob->paramExecTypes = lappend_oid(root->glob->paramExecTypes, |
574 | 11.6k | paramtype); |
575 | 11.6k | retval->paramtype = paramtype; |
576 | 11.6k | retval->paramtypmod = paramtypmod; |
577 | 11.6k | retval->paramcollid = paramcollation; |
578 | 11.6k | retval->location = -1; |
579 | | |
580 | 11.6k | return retval; |
581 | 11.6k | } |
582 | | |
583 | | /* |
584 | | * Assign a (nonnegative) PARAM_EXEC ID for a special parameter (one that |
585 | | * is not actually used to carry a value at runtime). Such parameters are |
586 | | * used for special runtime signaling purposes, such as connecting a |
587 | | * recursive union node to its worktable scan node or forcing plan |
588 | | * re-evaluation within the EvalPlanQual mechanism. No actual Param node |
589 | | * exists with this ID, however. |
590 | | */ |
591 | | int |
592 | | assign_special_exec_param(PlannerInfo *root) |
593 | 152k | { |
594 | 152k | int paramId = list_length(root->glob->paramExecTypes); |
595 | | |
596 | 152k | root->glob->paramExecTypes = lappend_oid(root->glob->paramExecTypes, |
597 | 152k | InvalidOid); |
598 | 152k | return paramId; |
599 | 152k | } |