Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * subselect.c
4 : * Planning routines for subselects.
5 : *
6 : * This module deals with SubLinks and CTEs, but not subquery RTEs (i.e.,
7 : * not sub-SELECT-in-FROM cases).
8 : *
9 : * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
10 : * Portions Copyright (c) 1994, Regents of the University of California
11 : *
12 : * IDENTIFICATION
13 : * src/backend/optimizer/plan/subselect.c
14 : *
15 : *-------------------------------------------------------------------------
16 : */
17 : #include "postgres.h"
18 :
19 : #include "access/htup_details.h"
20 : #include "catalog/pg_operator.h"
21 : #include "catalog/pg_type.h"
22 : #include "executor/executor.h"
23 : #include "miscadmin.h"
24 : #include "nodes/makefuncs.h"
25 : #include "nodes/nodeFuncs.h"
26 : #include "optimizer/clauses.h"
27 : #include "optimizer/cost.h"
28 : #include "optimizer/optimizer.h"
29 : #include "optimizer/paramassign.h"
30 : #include "optimizer/pathnode.h"
31 : #include "optimizer/planmain.h"
32 : #include "optimizer/planner.h"
33 : #include "optimizer/prep.h"
34 : #include "optimizer/subselect.h"
35 : #include "parser/parse_relation.h"
36 : #include "rewrite/rewriteManip.h"
37 : #include "utils/builtins.h"
38 : #include "utils/lsyscache.h"
39 : #include "utils/syscache.h"
40 :
41 :
42 : typedef struct convert_testexpr_context
43 : {
44 : PlannerInfo *root;
45 : List *subst_nodes; /* Nodes to substitute for Params */
46 : } convert_testexpr_context;
47 :
48 : typedef struct process_sublinks_context
49 : {
50 : PlannerInfo *root;
51 : bool isTopQual;
52 : } process_sublinks_context;
53 :
54 : typedef struct finalize_primnode_context
55 : {
56 : PlannerInfo *root;
57 : Bitmapset *paramids; /* Non-local PARAM_EXEC paramids found */
58 : } finalize_primnode_context;
59 :
60 : typedef struct inline_cte_walker_context
61 : {
62 : const char *ctename; /* name and relative level of target CTE */
63 : int levelsup;
64 : Query *ctequery; /* query to substitute */
65 : } inline_cte_walker_context;
66 :
67 :
68 : static Node *build_subplan(PlannerInfo *root, Plan *plan, Path *path,
69 : PlannerInfo *subroot, List *plan_params,
70 : SubLinkType subLinkType, int subLinkId,
71 : Node *testexpr, List *testexpr_paramids,
72 : bool unknownEqFalse);
73 : static List *generate_subquery_params(PlannerInfo *root, List *tlist,
74 : List **paramIds);
75 : static List *generate_subquery_vars(PlannerInfo *root, List *tlist,
76 : Index varno);
77 : static Node *convert_testexpr(PlannerInfo *root,
78 : Node *testexpr,
79 : List *subst_nodes);
80 : static Node *convert_testexpr_mutator(Node *node,
81 : convert_testexpr_context *context);
82 : static bool subplan_is_hashable(Plan *plan);
83 : static bool subpath_is_hashable(Path *path);
84 : static bool testexpr_is_hashable(Node *testexpr, List *param_ids);
85 : static bool test_opexpr_is_hashable(OpExpr *testexpr, List *param_ids);
86 : static bool hash_ok_operator(OpExpr *expr);
87 : static bool contain_dml(Node *node);
88 : static bool contain_dml_walker(Node *node, void *context);
89 : static bool contain_outer_selfref(Node *node);
90 : static bool contain_outer_selfref_walker(Node *node, Index *depth);
91 : static void inline_cte(PlannerInfo *root, CommonTableExpr *cte);
92 : static bool inline_cte_walker(Node *node, inline_cte_walker_context *context);
93 : static bool simplify_EXISTS_query(PlannerInfo *root, Query *query);
94 : static Query *convert_EXISTS_to_ANY(PlannerInfo *root, Query *subselect,
95 : Node **testexpr, List **paramIds);
96 : static Node *replace_correlation_vars_mutator(Node *node, PlannerInfo *root);
97 : static Node *process_sublinks_mutator(Node *node,
98 : process_sublinks_context *context);
99 : static Bitmapset *finalize_plan(PlannerInfo *root,
100 : Plan *plan,
101 : int gather_param,
102 : Bitmapset *valid_params,
103 : Bitmapset *scan_params);
104 : static bool finalize_primnode(Node *node, finalize_primnode_context *context);
105 : static bool finalize_agg_primnode(Node *node, finalize_primnode_context *context);
106 :
107 :
108 : /*
109 : * Get the datatype/typmod/collation of the first column of the plan's output.
110 : *
111 : * This information is stored for ARRAY_SUBLINK execution and for
112 : * exprType()/exprTypmod()/exprCollation(), which have no way to get at the
113 : * plan associated with a SubPlan node. We really only need the info for
114 : * EXPR_SUBLINK and ARRAY_SUBLINK subplans, but for consistency we save it
115 : * always.
116 : */
117 : static void
118 45710 : get_first_col_type(Plan *plan, Oid *coltype, int32 *coltypmod,
119 : Oid *colcollation)
120 : {
121 : /* In cases such as EXISTS, tlist might be empty; arbitrarily use VOID */
122 45710 : if (plan->targetlist)
123 : {
124 42830 : TargetEntry *tent = linitial_node(TargetEntry, plan->targetlist);
125 :
126 42830 : if (!tent->resjunk)
127 : {
128 42830 : *coltype = exprType((Node *) tent->expr);
129 42830 : *coltypmod = exprTypmod((Node *) tent->expr);
130 42830 : *colcollation = exprCollation((Node *) tent->expr);
131 42830 : return;
132 : }
133 : }
134 2880 : *coltype = VOIDOID;
135 2880 : *coltypmod = -1;
136 2880 : *colcollation = InvalidOid;
137 : }
138 :
139 : /*
140 : * Convert a SubLink (as created by the parser) into a SubPlan.
141 : *
142 : * We are given the SubLink's contained query, type, ID, and testexpr. We are
143 : * also told if this expression appears at top level of a WHERE/HAVING qual.
144 : *
145 : * Note: we assume that the testexpr has been AND/OR flattened (actually,
146 : * it's been through eval_const_expressions), but not converted to
147 : * implicit-AND form; and any SubLinks in it should already have been
148 : * converted to SubPlans. The subquery is as yet untouched, however.
149 : *
150 : * The result is whatever we need to substitute in place of the SubLink node
151 : * in the executable expression. If we're going to do the subplan as a
152 : * regular subplan, this will be the constructed SubPlan node. If we're going
153 : * to do the subplan as an InitPlan, the SubPlan node instead goes into
154 : * root->init_plans, and what we return here is an expression tree
155 : * representing the InitPlan's result: usually just a Param node representing
156 : * a single scalar result, but possibly a row comparison tree containing
157 : * multiple Param nodes, or for a MULTIEXPR subquery a simple NULL constant
158 : * (since the real output Params are elsewhere in the tree, and the MULTIEXPR
159 : * subquery itself is in a resjunk tlist entry whose value is uninteresting).
160 : */
161 : static Node *
162 41056 : make_subplan(PlannerInfo *root, Query *orig_subquery,
163 : SubLinkType subLinkType, int subLinkId,
164 : Node *testexpr, bool isTopQual)
165 : {
166 : Query *subquery;
167 41056 : bool simple_exists = false;
168 : double tuple_fraction;
169 : PlannerInfo *subroot;
170 : RelOptInfo *final_rel;
171 : Path *best_path;
172 : Plan *plan;
173 : List *plan_params;
174 : Node *result;
175 :
176 : /*
177 : * Copy the source Query node. This is a quick and dirty kluge to resolve
178 : * the fact that the parser can generate trees with multiple links to the
179 : * same sub-Query node, but the planner wants to scribble on the Query.
180 : * Try to clean this up when we do querytree redesign...
181 : */
182 41056 : subquery = copyObject(orig_subquery);
183 :
184 : /*
185 : * If it's an EXISTS subplan, we might be able to simplify it.
186 : */
187 41056 : if (subLinkType == EXISTS_SUBLINK)
188 2630 : simple_exists = simplify_EXISTS_query(root, subquery);
189 :
190 : /*
191 : * For an EXISTS subplan, tell lower-level planner to expect that only the
192 : * first tuple will be retrieved. For ALL and ANY subplans, we will be
193 : * able to stop evaluating if the test condition fails or matches, so very
194 : * often not all the tuples will be retrieved; for lack of a better idea,
195 : * specify 50% retrieval. For EXPR, MULTIEXPR, and ROWCOMPARE subplans,
196 : * use default behavior (we're only expecting one row out, anyway).
197 : *
198 : * NOTE: if you change these numbers, also change cost_subplan() in
199 : * path/costsize.c.
200 : *
201 : * XXX If an ANY subplan is uncorrelated, build_subplan may decide to hash
202 : * its output. In that case it would've been better to specify full
203 : * retrieval. At present, however, we can only check hashability after
204 : * we've made the subplan :-(. (Determining whether it'll fit in hash_mem
205 : * is the really hard part.) Therefore, we don't want to be too
206 : * optimistic about the percentage of tuples retrieved, for fear of
207 : * selecting a plan that's bad for the materialization case.
208 : */
209 41056 : if (subLinkType == EXISTS_SUBLINK)
210 2630 : tuple_fraction = 1.0; /* just like a LIMIT 1 */
211 38426 : else if (subLinkType == ALL_SUBLINK ||
212 : subLinkType == ANY_SUBLINK)
213 540 : tuple_fraction = 0.5; /* 50% */
214 : else
215 37886 : tuple_fraction = 0.0; /* default behavior */
216 :
217 : /* plan_params should not be in use in current query level */
218 : Assert(root->plan_params == NIL);
219 :
220 : /* Generate Paths for the subquery */
221 41056 : subroot = subquery_planner(root->glob, subquery, root, false,
222 : tuple_fraction, NULL);
223 :
224 : /* Isolate the params needed by this specific subplan */
225 41056 : plan_params = root->plan_params;
226 41056 : root->plan_params = NIL;
227 :
228 : /*
229 : * Select best Path and turn it into a Plan. At least for now, there
230 : * seems no reason to postpone doing that.
231 : */
232 41056 : final_rel = fetch_upper_rel(subroot, UPPERREL_FINAL, NULL);
233 41056 : best_path = get_cheapest_fractional_path(final_rel, tuple_fraction);
234 :
235 41056 : plan = create_plan(subroot, best_path);
236 :
237 : /* And convert to SubPlan or InitPlan format. */
238 41056 : result = build_subplan(root, plan, best_path,
239 : subroot, plan_params,
240 : subLinkType, subLinkId,
241 : testexpr, NIL, isTopQual);
242 :
243 : /*
244 : * If it's a correlated EXISTS with an unimportant targetlist, we might be
245 : * able to transform it to the equivalent of an IN and then implement it
246 : * by hashing. We don't have enough information yet to tell which way is
247 : * likely to be better (it depends on the expected number of executions of
248 : * the EXISTS qual, and we are much too early in planning the outer query
249 : * to be able to guess that). So we generate both plans, if possible, and
250 : * leave it to setrefs.c to decide which to use.
251 : */
252 41056 : if (simple_exists && IsA(result, SubPlan))
253 : {
254 : Node *newtestexpr;
255 : List *paramIds;
256 :
257 : /* Make a second copy of the original subquery */
258 2330 : subquery = copyObject(orig_subquery);
259 : /* and re-simplify */
260 2330 : simple_exists = simplify_EXISTS_query(root, subquery);
261 : Assert(simple_exists);
262 : /* See if it can be converted to an ANY query */
263 2330 : subquery = convert_EXISTS_to_ANY(root, subquery,
264 : &newtestexpr, ¶mIds);
265 2330 : if (subquery)
266 : {
267 : /* Generate Paths for the ANY subquery; we'll need all rows */
268 1768 : subroot = subquery_planner(root->glob, subquery, root, false, 0.0,
269 : NULL);
270 :
271 : /* Isolate the params needed by this specific subplan */
272 1768 : plan_params = root->plan_params;
273 1768 : root->plan_params = NIL;
274 :
275 : /* Select best Path */
276 1768 : final_rel = fetch_upper_rel(subroot, UPPERREL_FINAL, NULL);
277 1768 : best_path = final_rel->cheapest_total_path;
278 :
279 : /* Now we can check if it'll fit in hash_mem */
280 1768 : if (subpath_is_hashable(best_path))
281 : {
282 : SubPlan *hashplan;
283 : AlternativeSubPlan *asplan;
284 :
285 : /* OK, finish planning the ANY subquery */
286 1768 : plan = create_plan(subroot, best_path);
287 :
288 : /* ... and convert to SubPlan format */
289 1768 : hashplan = castNode(SubPlan,
290 : build_subplan(root, plan, best_path,
291 : subroot, plan_params,
292 : ANY_SUBLINK, 0,
293 : newtestexpr,
294 : paramIds,
295 : true));
296 : /* Check we got what we expected */
297 : Assert(hashplan->parParam == NIL);
298 : Assert(hashplan->useHashTable);
299 :
300 : /* Leave it to setrefs.c to decide which plan to use */
301 1768 : asplan = makeNode(AlternativeSubPlan);
302 1768 : asplan->subplans = list_make2(result, hashplan);
303 1768 : result = (Node *) asplan;
304 1768 : root->hasAlternativeSubPlans = true;
305 : }
306 : }
307 : }
308 :
309 41056 : return result;
310 : }
311 :
312 : /*
313 : * Build a SubPlan node given the raw inputs --- subroutine for make_subplan
314 : *
315 : * Returns either the SubPlan, or a replacement expression if we decide to
316 : * make it an InitPlan, as explained in the comments for make_subplan.
317 : */
318 : static Node *
319 42824 : build_subplan(PlannerInfo *root, Plan *plan, Path *path,
320 : PlannerInfo *subroot, List *plan_params,
321 : SubLinkType subLinkType, int subLinkId,
322 : Node *testexpr, List *testexpr_paramids,
323 : bool unknownEqFalse)
324 : {
325 : Node *result;
326 : SubPlan *splan;
327 : bool isInitPlan;
328 : ListCell *lc;
329 :
330 : /*
331 : * Initialize the SubPlan node. Note plan_id, plan_name, and cost fields
332 : * are set further down.
333 : */
334 42824 : splan = makeNode(SubPlan);
335 42824 : splan->subLinkType = subLinkType;
336 42824 : splan->testexpr = NULL;
337 42824 : splan->paramIds = NIL;
338 42824 : get_first_col_type(plan, &splan->firstColType, &splan->firstColTypmod,
339 : &splan->firstColCollation);
340 42824 : splan->useHashTable = false;
341 42824 : splan->unknownEqFalse = unknownEqFalse;
342 42824 : splan->parallel_safe = plan->parallel_safe;
343 42824 : splan->setParam = NIL;
344 42824 : splan->parParam = NIL;
345 42824 : splan->args = NIL;
346 :
347 : /*
348 : * Make parParam and args lists of param IDs and expressions that current
349 : * query level will pass to this child plan.
350 : */
351 89342 : foreach(lc, plan_params)
352 : {
353 46518 : PlannerParamItem *pitem = (PlannerParamItem *) lfirst(lc);
354 46518 : Node *arg = pitem->item;
355 :
356 : /*
357 : * The Var, PlaceHolderVar, Aggref, GroupingFunc, or ReturningExpr has
358 : * already been adjusted to have the correct varlevelsup, phlevelsup,
359 : * agglevelsup, or retlevelsup.
360 : *
361 : * If it's a PlaceHolderVar, Aggref, GroupingFunc, or ReturningExpr,
362 : * its arguments might contain SubLinks, which have not yet been
363 : * processed (see the comments for SS_replace_correlation_vars). Do
364 : * that now.
365 : */
366 46518 : if (IsA(arg, PlaceHolderVar) ||
367 46506 : IsA(arg, Aggref) ||
368 46454 : IsA(arg, GroupingFunc) ||
369 46390 : IsA(arg, ReturningExpr))
370 146 : arg = SS_process_sublinks(root, arg, false);
371 :
372 46518 : splan->parParam = lappend_int(splan->parParam, pitem->paramId);
373 46518 : splan->args = lappend(splan->args, arg);
374 : }
375 :
376 : /*
377 : * Un-correlated or undirect correlated plans of EXISTS, EXPR, ARRAY,
378 : * ROWCOMPARE, or MULTIEXPR types can be used as initPlans. For EXISTS,
379 : * EXPR, or ARRAY, we return a Param referring to the result of evaluating
380 : * the initPlan. For ROWCOMPARE, we must modify the testexpr tree to
381 : * contain PARAM_EXEC Params instead of the PARAM_SUBLINK Params emitted
382 : * by the parser, and then return that tree. For MULTIEXPR, we return a
383 : * null constant: the resjunk targetlist item containing the SubLink does
384 : * not need to return anything useful, since the referencing Params are
385 : * elsewhere.
386 : */
387 42824 : if (splan->parParam == NIL && subLinkType == EXISTS_SUBLINK)
388 268 : {
389 : Param *prm;
390 :
391 : Assert(testexpr == NULL);
392 268 : prm = generate_new_exec_param(root, BOOLOID, -1, InvalidOid);
393 268 : splan->setParam = list_make1_int(prm->paramid);
394 268 : isInitPlan = true;
395 268 : result = (Node *) prm;
396 : }
397 42556 : else if (splan->parParam == NIL && subLinkType == EXPR_SUBLINK)
398 10204 : {
399 10204 : TargetEntry *te = linitial(plan->targetlist);
400 : Param *prm;
401 :
402 : Assert(!te->resjunk);
403 : Assert(testexpr == NULL);
404 10204 : prm = generate_new_exec_param(root,
405 10204 : exprType((Node *) te->expr),
406 10204 : exprTypmod((Node *) te->expr),
407 10204 : exprCollation((Node *) te->expr));
408 10204 : splan->setParam = list_make1_int(prm->paramid);
409 10204 : isInitPlan = true;
410 10204 : result = (Node *) prm;
411 : }
412 32352 : else if (splan->parParam == NIL && subLinkType == ARRAY_SUBLINK)
413 122 : {
414 122 : TargetEntry *te = linitial(plan->targetlist);
415 : Oid arraytype;
416 : Param *prm;
417 :
418 : Assert(!te->resjunk);
419 : Assert(testexpr == NULL);
420 122 : arraytype = get_promoted_array_type(exprType((Node *) te->expr));
421 122 : if (!OidIsValid(arraytype))
422 0 : elog(ERROR, "could not find array type for datatype %s",
423 : format_type_be(exprType((Node *) te->expr)));
424 122 : prm = generate_new_exec_param(root,
425 : arraytype,
426 122 : exprTypmod((Node *) te->expr),
427 122 : exprCollation((Node *) te->expr));
428 122 : splan->setParam = list_make1_int(prm->paramid);
429 122 : isInitPlan = true;
430 122 : result = (Node *) prm;
431 : }
432 32230 : else if (splan->parParam == NIL && subLinkType == ROWCOMPARE_SUBLINK)
433 18 : {
434 : /* Adjust the Params */
435 : List *params;
436 :
437 : Assert(testexpr != NULL);
438 18 : params = generate_subquery_params(root,
439 : plan->targetlist,
440 : &splan->paramIds);
441 18 : result = convert_testexpr(root,
442 : testexpr,
443 : params);
444 18 : splan->setParam = list_copy(splan->paramIds);
445 18 : isInitPlan = true;
446 :
447 : /*
448 : * The executable expression is returned to become part of the outer
449 : * plan's expression tree; it is not kept in the initplan node.
450 : */
451 : }
452 32212 : else if (subLinkType == MULTIEXPR_SUBLINK)
453 : {
454 : /*
455 : * Whether it's an initplan or not, it needs to set a PARAM_EXEC Param
456 : * for each output column.
457 : */
458 : List *params;
459 :
460 : Assert(testexpr == NULL);
461 132 : params = generate_subquery_params(root,
462 : plan->targetlist,
463 : &splan->setParam);
464 :
465 : /*
466 : * Save the list of replacement Params in the n'th cell of
467 : * root->multiexpr_params; setrefs.c will use it to replace
468 : * PARAM_MULTIEXPR Params.
469 : */
470 264 : while (list_length(root->multiexpr_params) < subLinkId)
471 132 : root->multiexpr_params = lappend(root->multiexpr_params, NIL);
472 132 : lc = list_nth_cell(root->multiexpr_params, subLinkId - 1);
473 : Assert(lfirst(lc) == NIL);
474 132 : lfirst(lc) = params;
475 :
476 : /* It can be an initplan if there are no parParams. */
477 132 : if (splan->parParam == NIL)
478 : {
479 30 : isInitPlan = true;
480 30 : result = (Node *) makeNullConst(RECORDOID, -1, InvalidOid);
481 : }
482 : else
483 : {
484 102 : isInitPlan = false;
485 102 : result = (Node *) splan;
486 : }
487 : }
488 : else
489 : {
490 : /*
491 : * Adjust the Params in the testexpr, unless caller already took care
492 : * of it (as indicated by passing a list of Param IDs).
493 : */
494 32080 : if (testexpr && testexpr_paramids == NIL)
495 552 : {
496 : List *params;
497 :
498 552 : params = generate_subquery_params(root,
499 : plan->targetlist,
500 : &splan->paramIds);
501 552 : splan->testexpr = convert_testexpr(root,
502 : testexpr,
503 : params);
504 : }
505 : else
506 : {
507 31528 : splan->testexpr = testexpr;
508 31528 : splan->paramIds = testexpr_paramids;
509 : }
510 :
511 : /*
512 : * We can't convert subplans of ALL_SUBLINK or ANY_SUBLINK types to
513 : * initPlans, even when they are uncorrelated or undirect correlated,
514 : * because we need to scan the output of the subplan for each outer
515 : * tuple. But if it's a not-direct-correlated IN (= ANY) test, we
516 : * might be able to use a hashtable to avoid comparing all the tuples.
517 : */
518 32080 : if (subLinkType == ANY_SUBLINK &&
519 4488 : splan->parParam == NIL &&
520 4396 : subplan_is_hashable(plan) &&
521 2198 : testexpr_is_hashable(splan->testexpr, splan->paramIds))
522 2174 : splan->useHashTable = true;
523 :
524 : /*
525 : * Otherwise, we have the option to tack a Material node onto the top
526 : * of the subplan, to reduce the cost of reading it repeatedly. This
527 : * is pointless for a direct-correlated subplan, since we'd have to
528 : * recompute its results each time anyway. For uncorrelated/undirect
529 : * correlated subplans, we add Material unless the subplan's top plan
530 : * node would materialize its output anyway. Also, if enable_material
531 : * is false, then the user does not want us to materialize anything
532 : * unnecessarily, so we don't.
533 : */
534 29906 : else if (splan->parParam == NIL && enable_material &&
535 42 : !ExecMaterializesOutput(nodeTag(plan)))
536 42 : plan = materialize_finished_plan(plan);
537 :
538 32080 : result = (Node *) splan;
539 32080 : isInitPlan = false;
540 : }
541 :
542 : /*
543 : * Add the subplan, its path, and its PlannerInfo to the global lists.
544 : */
545 42824 : root->glob->subplans = lappend(root->glob->subplans, plan);
546 42824 : root->glob->subpaths = lappend(root->glob->subpaths, path);
547 42824 : root->glob->subroots = lappend(root->glob->subroots, subroot);
548 42824 : splan->plan_id = list_length(root->glob->subplans);
549 :
550 42824 : if (isInitPlan)
551 10642 : root->init_plans = lappend(root->init_plans, splan);
552 :
553 : /*
554 : * A parameterless subplan (not initplan) should be prepared to handle
555 : * REWIND efficiently. If it has direct parameters then there's no point
556 : * since it'll be reset on each scan anyway; and if it's an initplan then
557 : * there's no point since it won't get re-run without parameter changes
558 : * anyway. The input of a hashed subplan doesn't need REWIND either.
559 : */
560 42824 : if (splan->parParam == NIL && !isInitPlan && !splan->useHashTable)
561 42 : root->glob->rewindPlanIDs = bms_add_member(root->glob->rewindPlanIDs,
562 : splan->plan_id);
563 :
564 : /* Label the subplan for EXPLAIN purposes */
565 42824 : splan->plan_name = psprintf("%s %d",
566 : isInitPlan ? "InitPlan" : "SubPlan",
567 : splan->plan_id);
568 :
569 : /* Lastly, fill in the cost estimates for use later */
570 42824 : cost_subplan(root, splan, plan);
571 :
572 42824 : return result;
573 : }
574 :
575 : /*
576 : * generate_subquery_params: build a list of Params representing the output
577 : * columns of a sublink's sub-select, given the sub-select's targetlist.
578 : *
579 : * We also return an integer list of the paramids of the Params.
580 : */
581 : static List *
582 702 : generate_subquery_params(PlannerInfo *root, List *tlist, List **paramIds)
583 : {
584 : List *result;
585 : List *ids;
586 : ListCell *lc;
587 :
588 702 : result = ids = NIL;
589 1652 : foreach(lc, tlist)
590 : {
591 950 : TargetEntry *tent = (TargetEntry *) lfirst(lc);
592 : Param *param;
593 :
594 950 : if (tent->resjunk)
595 6 : continue;
596 :
597 944 : param = generate_new_exec_param(root,
598 944 : exprType((Node *) tent->expr),
599 944 : exprTypmod((Node *) tent->expr),
600 944 : exprCollation((Node *) tent->expr));
601 944 : result = lappend(result, param);
602 944 : ids = lappend_int(ids, param->paramid);
603 : }
604 :
605 702 : *paramIds = ids;
606 702 : return result;
607 : }
608 :
609 : /*
610 : * generate_subquery_vars: build a list of Vars representing the output
611 : * columns of a sublink's sub-select, given the sub-select's targetlist.
612 : * The Vars have the specified varno (RTE index).
613 : */
614 : static List *
615 4306 : generate_subquery_vars(PlannerInfo *root, List *tlist, Index varno)
616 : {
617 : List *result;
618 : ListCell *lc;
619 :
620 4306 : result = NIL;
621 8666 : foreach(lc, tlist)
622 : {
623 4360 : TargetEntry *tent = (TargetEntry *) lfirst(lc);
624 : Var *var;
625 :
626 4360 : if (tent->resjunk)
627 0 : continue;
628 :
629 4360 : var = makeVarFromTargetEntry(varno, tent);
630 4360 : result = lappend(result, var);
631 : }
632 :
633 4306 : return result;
634 : }
635 :
636 : /*
637 : * convert_testexpr: convert the testexpr given by the parser into
638 : * actually executable form. This entails replacing PARAM_SUBLINK Params
639 : * with Params or Vars representing the results of the sub-select. The
640 : * nodes to be substituted are passed in as the List result from
641 : * generate_subquery_params or generate_subquery_vars.
642 : */
643 : static Node *
644 5152 : convert_testexpr(PlannerInfo *root,
645 : Node *testexpr,
646 : List *subst_nodes)
647 : {
648 : convert_testexpr_context context;
649 :
650 5152 : context.root = root;
651 5152 : context.subst_nodes = subst_nodes;
652 5152 : return convert_testexpr_mutator(testexpr, &context);
653 : }
654 :
655 : static Node *
656 24538 : convert_testexpr_mutator(Node *node,
657 : convert_testexpr_context *context)
658 : {
659 24538 : if (node == NULL)
660 46 : return NULL;
661 24492 : if (IsA(node, Param))
662 : {
663 5336 : Param *param = (Param *) node;
664 :
665 5336 : if (param->paramkind == PARAM_SUBLINK)
666 : {
667 10660 : if (param->paramid <= 0 ||
668 5330 : param->paramid > list_length(context->subst_nodes))
669 0 : elog(ERROR, "unexpected PARAM_SUBLINK ID: %d", param->paramid);
670 :
671 : /*
672 : * We copy the list item to avoid having doubly-linked
673 : * substructure in the modified parse tree. This is probably
674 : * unnecessary when it's a Param, but be safe.
675 : */
676 5330 : return (Node *) copyObject(list_nth(context->subst_nodes,
677 : param->paramid - 1));
678 : }
679 : }
680 19162 : if (IsA(node, SubLink))
681 : {
682 : /*
683 : * If we come across a nested SubLink, it is neither necessary nor
684 : * correct to recurse into it: any PARAM_SUBLINKs we might find inside
685 : * belong to the inner SubLink not the outer. So just return it as-is.
686 : *
687 : * This reasoning depends on the assumption that nothing will pull
688 : * subexpressions into or out of the testexpr field of a SubLink, at
689 : * least not without replacing PARAM_SUBLINKs first. If we did want
690 : * to do that we'd need to rethink the parser-output representation
691 : * altogether, since currently PARAM_SUBLINKs are only unique per
692 : * SubLink not globally across the query. The whole point of
693 : * replacing them with Vars or PARAM_EXEC nodes is to make them
694 : * globally unique before they escape from the SubLink's testexpr.
695 : *
696 : * Note: this can't happen when called during SS_process_sublinks,
697 : * because that recursively processes inner SubLinks first. It can
698 : * happen when called from convert_ANY_sublink_to_join, though.
699 : */
700 12 : return node;
701 : }
702 19150 : return expression_tree_mutator(node, convert_testexpr_mutator, context);
703 : }
704 :
705 : /*
706 : * subplan_is_hashable: can we implement an ANY subplan by hashing?
707 : *
708 : * This is not responsible for checking whether the combining testexpr
709 : * is suitable for hashing. We only look at the subquery itself.
710 : */
711 : static bool
712 2198 : subplan_is_hashable(Plan *plan)
713 : {
714 : double subquery_size;
715 :
716 : /*
717 : * The estimated size of the subquery result must fit in hash_mem. (Note:
718 : * we use heap tuple overhead here even though the tuples will actually be
719 : * stored as MinimalTuples; this provides some fudge factor for hashtable
720 : * overhead.)
721 : */
722 2198 : subquery_size = plan->plan_rows *
723 2198 : (MAXALIGN(plan->plan_width) + MAXALIGN(SizeofHeapTupleHeader));
724 2198 : if (subquery_size > get_hash_memory_limit())
725 0 : return false;
726 :
727 2198 : return true;
728 : }
729 :
730 : /*
731 : * subpath_is_hashable: can we implement an ANY subplan by hashing?
732 : *
733 : * Identical to subplan_is_hashable, but work from a Path for the subplan.
734 : */
735 : static bool
736 1768 : subpath_is_hashable(Path *path)
737 : {
738 : double subquery_size;
739 :
740 : /*
741 : * The estimated size of the subquery result must fit in hash_mem. (Note:
742 : * we use heap tuple overhead here even though the tuples will actually be
743 : * stored as MinimalTuples; this provides some fudge factor for hashtable
744 : * overhead.)
745 : */
746 1768 : subquery_size = path->rows *
747 1768 : (MAXALIGN(path->pathtarget->width) + MAXALIGN(SizeofHeapTupleHeader));
748 1768 : if (subquery_size > get_hash_memory_limit())
749 0 : return false;
750 :
751 1768 : return true;
752 : }
753 :
754 : /*
755 : * testexpr_is_hashable: is an ANY SubLink's test expression hashable?
756 : *
757 : * To identify LHS vs RHS of the hash expression, we must be given the
758 : * list of output Param IDs of the SubLink's subquery.
759 : */
760 : static bool
761 2198 : testexpr_is_hashable(Node *testexpr, List *param_ids)
762 : {
763 : /*
764 : * The testexpr must be a single OpExpr, or an AND-clause containing only
765 : * OpExprs, each of which satisfy test_opexpr_is_hashable().
766 : */
767 2198 : if (testexpr && IsA(testexpr, OpExpr))
768 : {
769 1332 : if (test_opexpr_is_hashable((OpExpr *) testexpr, param_ids))
770 1308 : return true;
771 : }
772 866 : else if (is_andclause(testexpr))
773 : {
774 : ListCell *l;
775 :
776 2598 : foreach(l, ((BoolExpr *) testexpr)->args)
777 : {
778 1732 : Node *andarg = (Node *) lfirst(l);
779 :
780 1732 : if (!IsA(andarg, OpExpr))
781 0 : return false;
782 1732 : if (!test_opexpr_is_hashable((OpExpr *) andarg, param_ids))
783 0 : return false;
784 : }
785 866 : return true;
786 : }
787 :
788 24 : return false;
789 : }
790 :
791 : static bool
792 3064 : test_opexpr_is_hashable(OpExpr *testexpr, List *param_ids)
793 : {
794 : /*
795 : * The combining operator must be hashable and strict. The need for
796 : * hashability is obvious, since we want to use hashing. Without
797 : * strictness, behavior in the presence of nulls is too unpredictable. We
798 : * actually must assume even more than plain strictness: it can't yield
799 : * NULL for non-null inputs, either (see nodeSubplan.c). However, hash
800 : * indexes and hash joins assume that too.
801 : */
802 3064 : if (!hash_ok_operator(testexpr))
803 12 : return false;
804 :
805 : /*
806 : * The left and right inputs must belong to the outer and inner queries
807 : * respectively; hence Params that will be supplied by the subquery must
808 : * not appear in the LHS, and Vars of the outer query must not appear in
809 : * the RHS. (Ordinarily, this must be true because of the way that the
810 : * parser builds an ANY SubLink's testexpr ... but inlining of functions
811 : * could have changed the expression's structure, so we have to check.
812 : * Such cases do not occur often enough to be worth trying to optimize, so
813 : * we don't worry about trying to commute the clause or anything like
814 : * that; we just need to be sure not to build an invalid plan.)
815 : */
816 3052 : if (list_length(testexpr->args) != 2)
817 0 : return false;
818 3052 : if (contain_exec_param((Node *) linitial(testexpr->args), param_ids))
819 12 : return false;
820 3040 : if (contain_var_clause((Node *) lsecond(testexpr->args)))
821 0 : return false;
822 3040 : return true;
823 : }
824 :
825 : /*
826 : * Check expression is hashable + strict
827 : *
828 : * We could use op_hashjoinable() and op_strict(), but do it like this to
829 : * avoid a redundant cache lookup.
830 : */
831 : static bool
832 9530 : hash_ok_operator(OpExpr *expr)
833 : {
834 9530 : Oid opid = expr->opno;
835 :
836 : /* quick out if not a binary operator */
837 9530 : if (list_length(expr->args) != 2)
838 0 : return false;
839 9530 : if (opid == ARRAY_EQ_OP ||
840 : opid == RECORD_EQ_OP)
841 : {
842 : /* these are strict, but must check input type to ensure hashable */
843 12 : Node *leftarg = linitial(expr->args);
844 :
845 12 : return op_hashjoinable(opid, exprType(leftarg));
846 : }
847 : else
848 : {
849 : /* else must look up the operator properties */
850 : HeapTuple tup;
851 : Form_pg_operator optup;
852 :
853 9518 : tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(opid));
854 9518 : if (!HeapTupleIsValid(tup))
855 0 : elog(ERROR, "cache lookup failed for operator %u", opid);
856 9518 : optup = (Form_pg_operator) GETSTRUCT(tup);
857 9518 : if (!optup->oprcanhash || !func_strict(optup->oprcode))
858 : {
859 1082 : ReleaseSysCache(tup);
860 1082 : return false;
861 : }
862 8436 : ReleaseSysCache(tup);
863 8436 : return true;
864 : }
865 : }
866 :
867 :
868 : /*
869 : * SS_process_ctes: process a query's WITH list
870 : *
871 : * Consider each CTE in the WITH list and either ignore it (if it's an
872 : * unreferenced SELECT), "inline" it to create a regular sub-SELECT-in-FROM,
873 : * or convert it to an initplan.
874 : *
875 : * A side effect is to fill in root->cte_plan_ids with a list that
876 : * parallels root->parse->cteList and provides the subplan ID for
877 : * each CTE's initplan, or a dummy ID (-1) if we didn't make an initplan.
878 : */
879 : void
880 2882 : SS_process_ctes(PlannerInfo *root)
881 : {
882 : ListCell *lc;
883 :
884 : Assert(root->cte_plan_ids == NIL);
885 :
886 6902 : foreach(lc, root->parse->cteList)
887 : {
888 4026 : CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc);
889 4026 : CmdType cmdType = ((Query *) cte->ctequery)->commandType;
890 : Query *subquery;
891 : PlannerInfo *subroot;
892 : RelOptInfo *final_rel;
893 : Path *best_path;
894 : Plan *plan;
895 : SubPlan *splan;
896 : int paramid;
897 :
898 : /*
899 : * Ignore SELECT CTEs that are not actually referenced anywhere.
900 : */
901 4026 : if (cte->cterefcount == 0 && cmdType == CMD_SELECT)
902 : {
903 : /* Make a dummy entry in cte_plan_ids */
904 52 : root->cte_plan_ids = lappend_int(root->cte_plan_ids, -1);
905 1534 : continue;
906 : }
907 :
908 : /*
909 : * Consider inlining the CTE (creating RTE_SUBQUERY RTE(s)) instead of
910 : * implementing it as a separately-planned CTE.
911 : *
912 : * We cannot inline if any of these conditions hold:
913 : *
914 : * 1. The user said not to (the CTEMaterializeAlways option).
915 : *
916 : * 2. The CTE is recursive.
917 : *
918 : * 3. The CTE has side-effects; this includes either not being a plain
919 : * SELECT, or containing volatile functions. Inlining might change
920 : * the side-effects, which would be bad.
921 : *
922 : * 4. The CTE is multiply-referenced and contains a self-reference to
923 : * a recursive CTE outside itself. Inlining would result in multiple
924 : * recursive self-references, which we don't support.
925 : *
926 : * Otherwise, we have an option whether to inline or not. That should
927 : * always be a win if there's just a single reference, but if the CTE
928 : * is multiply-referenced then it's unclear: inlining adds duplicate
929 : * computations, but the ability to absorb restrictions from the outer
930 : * query level could outweigh that. We do not have nearly enough
931 : * information at this point to tell whether that's true, so we let
932 : * the user express a preference. Our default behavior is to inline
933 : * only singly-referenced CTEs, but a CTE marked CTEMaterializeNever
934 : * will be inlined even if multiply referenced.
935 : *
936 : * Note: we check for volatile functions last, because that's more
937 : * expensive than the other tests needed.
938 : */
939 3974 : if ((cte->ctematerialized == CTEMaterializeNever ||
940 3926 : (cte->ctematerialized == CTEMaterializeDefault &&
941 3724 : cte->cterefcount == 1)) &&
942 2784 : !cte->cterecursive &&
943 1574 : cmdType == CMD_SELECT &&
944 1574 : !contain_dml(cte->ctequery) &&
945 1566 : (cte->cterefcount <= 1 ||
946 36 : !contain_outer_selfref(cte->ctequery)) &&
947 1554 : !contain_volatile_functions(cte->ctequery))
948 : {
949 1482 : inline_cte(root, cte);
950 : /* Make a dummy entry in cte_plan_ids */
951 1482 : root->cte_plan_ids = lappend_int(root->cte_plan_ids, -1);
952 1482 : continue;
953 : }
954 :
955 : /*
956 : * Copy the source Query node. Probably not necessary, but let's keep
957 : * this similar to make_subplan.
958 : */
959 2492 : subquery = (Query *) copyObject(cte->ctequery);
960 :
961 : /* plan_params should not be in use in current query level */
962 : Assert(root->plan_params == NIL);
963 :
964 : /*
965 : * Generate Paths for the CTE query. Always plan for full retrieval
966 : * --- we don't have enough info to predict otherwise.
967 : */
968 2492 : subroot = subquery_planner(root->glob, subquery, root,
969 2492 : cte->cterecursive, 0.0, NULL);
970 :
971 : /*
972 : * Since the current query level doesn't yet contain any RTEs, it
973 : * should not be possible for the CTE to have requested parameters of
974 : * this level.
975 : */
976 2486 : if (root->plan_params)
977 0 : elog(ERROR, "unexpected outer reference in CTE query");
978 :
979 : /*
980 : * Select best Path and turn it into a Plan. At least for now, there
981 : * seems no reason to postpone doing that.
982 : */
983 2486 : final_rel = fetch_upper_rel(subroot, UPPERREL_FINAL, NULL);
984 2486 : best_path = final_rel->cheapest_total_path;
985 :
986 2486 : plan = create_plan(subroot, best_path);
987 :
988 : /*
989 : * Make a SubPlan node for it. This is just enough unlike
990 : * build_subplan that we can't share code.
991 : *
992 : * Note plan_id, plan_name, and cost fields are set further down.
993 : */
994 2486 : splan = makeNode(SubPlan);
995 2486 : splan->subLinkType = CTE_SUBLINK;
996 2486 : splan->testexpr = NULL;
997 2486 : splan->paramIds = NIL;
998 2486 : get_first_col_type(plan, &splan->firstColType, &splan->firstColTypmod,
999 : &splan->firstColCollation);
1000 2486 : splan->useHashTable = false;
1001 2486 : splan->unknownEqFalse = false;
1002 :
1003 : /*
1004 : * CTE scans are not considered for parallelism (cf
1005 : * set_rel_consider_parallel).
1006 : */
1007 2486 : splan->parallel_safe = false;
1008 2486 : splan->setParam = NIL;
1009 2486 : splan->parParam = NIL;
1010 2486 : splan->args = NIL;
1011 :
1012 : /*
1013 : * The node can't have any inputs (since it's an initplan), so the
1014 : * parParam and args lists remain empty. (It could contain references
1015 : * to earlier CTEs' output param IDs, but CTE outputs are not
1016 : * propagated via the args list.)
1017 : */
1018 :
1019 : /*
1020 : * Assign a param ID to represent the CTE's output. No ordinary
1021 : * "evaluation" of this param slot ever happens, but we use the param
1022 : * ID for setParam/chgParam signaling just as if the CTE plan were
1023 : * returning a simple scalar output. (Also, the executor abuses the
1024 : * ParamExecData slot for this param ID for communication among
1025 : * multiple CteScan nodes that might be scanning this CTE.)
1026 : */
1027 2486 : paramid = assign_special_exec_param(root);
1028 2486 : splan->setParam = list_make1_int(paramid);
1029 :
1030 : /*
1031 : * Add the subplan, its path, and its PlannerInfo to the global lists.
1032 : */
1033 2486 : root->glob->subplans = lappend(root->glob->subplans, plan);
1034 2486 : root->glob->subpaths = lappend(root->glob->subpaths, best_path);
1035 2486 : root->glob->subroots = lappend(root->glob->subroots, subroot);
1036 2486 : splan->plan_id = list_length(root->glob->subplans);
1037 :
1038 2486 : root->init_plans = lappend(root->init_plans, splan);
1039 :
1040 2486 : root->cte_plan_ids = lappend_int(root->cte_plan_ids, splan->plan_id);
1041 :
1042 : /* Label the subplan for EXPLAIN purposes */
1043 2486 : splan->plan_name = psprintf("CTE %s", cte->ctename);
1044 :
1045 : /* Lastly, fill in the cost estimates for use later */
1046 2486 : cost_subplan(root, splan, plan);
1047 : }
1048 2876 : }
1049 :
1050 : /*
1051 : * contain_dml: is any subquery not a plain SELECT?
1052 : *
1053 : * We reject SELECT FOR UPDATE/SHARE as well as INSERT etc.
1054 : */
1055 : static bool
1056 1574 : contain_dml(Node *node)
1057 : {
1058 1574 : return contain_dml_walker(node, NULL);
1059 : }
1060 :
1061 : static bool
1062 106096 : contain_dml_walker(Node *node, void *context)
1063 : {
1064 106096 : if (node == NULL)
1065 36204 : return false;
1066 69892 : if (IsA(node, Query))
1067 : {
1068 2846 : Query *query = (Query *) node;
1069 :
1070 2846 : if (query->commandType != CMD_SELECT ||
1071 2846 : query->rowMarks != NIL)
1072 8 : return true;
1073 :
1074 2838 : return query_tree_walker(query, contain_dml_walker, context, 0);
1075 : }
1076 67046 : return expression_tree_walker(node, contain_dml_walker, context);
1077 : }
1078 :
1079 : /*
1080 : * contain_outer_selfref: is there an external recursive self-reference?
1081 : */
1082 : static bool
1083 36 : contain_outer_selfref(Node *node)
1084 : {
1085 36 : Index depth = 0;
1086 :
1087 : /*
1088 : * We should be starting with a Query, so that depth will be 1 while
1089 : * examining its immediate contents.
1090 : */
1091 : Assert(IsA(node, Query));
1092 :
1093 36 : return contain_outer_selfref_walker(node, &depth);
1094 : }
1095 :
1096 : static bool
1097 810 : contain_outer_selfref_walker(Node *node, Index *depth)
1098 : {
1099 810 : if (node == NULL)
1100 486 : return false;
1101 324 : if (IsA(node, RangeTblEntry))
1102 : {
1103 30 : RangeTblEntry *rte = (RangeTblEntry *) node;
1104 :
1105 : /*
1106 : * Check for a self-reference to a CTE that's above the Query that our
1107 : * search started at.
1108 : */
1109 30 : if (rte->rtekind == RTE_CTE &&
1110 12 : rte->self_reference &&
1111 12 : rte->ctelevelsup >= *depth)
1112 12 : return true;
1113 18 : return false; /* allow range_table_walker to continue */
1114 : }
1115 294 : if (IsA(node, Query))
1116 : {
1117 : /* Recurse into subquery, tracking nesting depth properly */
1118 42 : Query *query = (Query *) node;
1119 : bool result;
1120 :
1121 42 : (*depth)++;
1122 :
1123 42 : result = query_tree_walker(query, contain_outer_selfref_walker,
1124 : depth, QTW_EXAMINE_RTES_BEFORE);
1125 :
1126 42 : (*depth)--;
1127 :
1128 42 : return result;
1129 : }
1130 252 : return expression_tree_walker(node, contain_outer_selfref_walker, depth);
1131 : }
1132 :
1133 : /*
1134 : * inline_cte: convert RTE_CTE references to given CTE into RTE_SUBQUERYs
1135 : */
1136 : static void
1137 1482 : inline_cte(PlannerInfo *root, CommonTableExpr *cte)
1138 : {
1139 : struct inline_cte_walker_context context;
1140 :
1141 1482 : context.ctename = cte->ctename;
1142 : /* Start at levelsup = -1 because we'll immediately increment it */
1143 1482 : context.levelsup = -1;
1144 1482 : context.ctequery = castNode(Query, cte->ctequery);
1145 :
1146 1482 : (void) inline_cte_walker((Node *) root->parse, &context);
1147 1482 : }
1148 :
1149 : static bool
1150 550806 : inline_cte_walker(Node *node, inline_cte_walker_context *context)
1151 : {
1152 550806 : if (node == NULL)
1153 146900 : return false;
1154 403906 : if (IsA(node, Query))
1155 : {
1156 10754 : Query *query = (Query *) node;
1157 :
1158 10754 : context->levelsup++;
1159 :
1160 : /*
1161 : * Visit the query's RTE nodes after their contents; otherwise
1162 : * query_tree_walker would descend into the newly inlined CTE query,
1163 : * which we don't want.
1164 : */
1165 10754 : (void) query_tree_walker(query, inline_cte_walker, context,
1166 : QTW_EXAMINE_RTES_AFTER);
1167 :
1168 10754 : context->levelsup--;
1169 :
1170 10754 : return false;
1171 : }
1172 393152 : else if (IsA(node, RangeTblEntry))
1173 : {
1174 20266 : RangeTblEntry *rte = (RangeTblEntry *) node;
1175 :
1176 20266 : if (rte->rtekind == RTE_CTE &&
1177 5988 : strcmp(rte->ctename, context->ctename) == 0 &&
1178 1512 : rte->ctelevelsup == context->levelsup)
1179 : {
1180 : /*
1181 : * Found a reference to replace. Generate a copy of the CTE query
1182 : * with appropriate level adjustment for outer references (e.g.,
1183 : * to other CTEs).
1184 : */
1185 1506 : Query *newquery = copyObject(context->ctequery);
1186 :
1187 1506 : if (context->levelsup > 0)
1188 944 : IncrementVarSublevelsUp((Node *) newquery, context->levelsup, 1);
1189 :
1190 : /*
1191 : * Convert the RTE_CTE RTE into a RTE_SUBQUERY.
1192 : *
1193 : * Historically, a FOR UPDATE clause has been treated as extending
1194 : * into views and subqueries, but not into CTEs. We preserve this
1195 : * distinction by not trying to push rowmarks into the new
1196 : * subquery.
1197 : */
1198 1506 : rte->rtekind = RTE_SUBQUERY;
1199 1506 : rte->subquery = newquery;
1200 1506 : rte->security_barrier = false;
1201 :
1202 : /* Zero out CTE-specific fields */
1203 1506 : rte->ctename = NULL;
1204 1506 : rte->ctelevelsup = 0;
1205 1506 : rte->self_reference = false;
1206 1506 : rte->coltypes = NIL;
1207 1506 : rte->coltypmods = NIL;
1208 1506 : rte->colcollations = NIL;
1209 : }
1210 :
1211 20266 : return false;
1212 : }
1213 :
1214 372886 : return expression_tree_walker(node, inline_cte_walker, context);
1215 : }
1216 :
1217 : /*
1218 : * Attempt to transform 'testexpr' over the VALUES subquery into
1219 : * a ScalarArrayOpExpr. We currently support the transformation only when
1220 : * it ends up with a constant array. Otherwise, the evaluation of non-hashed
1221 : * SAOP might be slower than the corresponding Hash Join with VALUES.
1222 : *
1223 : * Return transformed ScalarArrayOpExpr or NULL if transformation isn't
1224 : * allowed.
1225 : */
1226 : ScalarArrayOpExpr *
1227 4496 : convert_VALUES_to_ANY(PlannerInfo *root, Node *testexpr, Query *values)
1228 : {
1229 : RangeTblEntry *rte;
1230 : Node *leftop;
1231 : Node *rightop;
1232 : Oid opno;
1233 : ListCell *lc;
1234 : Oid inputcollid;
1235 4496 : List *exprs = NIL;
1236 :
1237 : /*
1238 : * Check we have a binary operator over a single-column subquery with no
1239 : * joins and no LIMIT/OFFSET/ORDER BY clauses.
1240 : */
1241 8910 : if (!IsA(testexpr, OpExpr) ||
1242 8828 : list_length(((OpExpr *) testexpr)->args) != 2 ||
1243 4414 : list_length(values->targetList) > 1 ||
1244 4414 : values->limitCount != NULL ||
1245 4402 : values->limitOffset != NULL ||
1246 8762 : values->sortClause != NIL ||
1247 4378 : list_length(values->rtable) != 1)
1248 3618 : return NULL;
1249 :
1250 878 : rte = linitial_node(RangeTblEntry, values->rtable);
1251 878 : leftop = linitial(((OpExpr *) testexpr)->args);
1252 878 : rightop = lsecond(((OpExpr *) testexpr)->args);
1253 878 : opno = ((OpExpr *) testexpr)->opno;
1254 878 : inputcollid = ((OpExpr *) testexpr)->inputcollid;
1255 :
1256 : /*
1257 : * Also, check that only RTE corresponds to VALUES; the list of values has
1258 : * at least two items and no volatile functions.
1259 : */
1260 1010 : if (rte->rtekind != RTE_VALUES ||
1261 252 : list_length(rte->values_lists) < 2 ||
1262 120 : contain_volatile_functions((Node *) rte->values_lists))
1263 758 : return NULL;
1264 :
1265 360 : foreach(lc, rte->values_lists)
1266 : {
1267 276 : List *elem = lfirst(lc);
1268 276 : Node *value = linitial(elem);
1269 :
1270 : /*
1271 : * Prepare an evaluation of the right side of the operator with
1272 : * substitution of the given value.
1273 : */
1274 276 : value = convert_testexpr(root, rightop, list_make1(value));
1275 :
1276 : /*
1277 : * Try to evaluate constant expressions. We could get Const as a
1278 : * result.
1279 : */
1280 276 : value = eval_const_expressions(root, value);
1281 :
1282 : /*
1283 : * As we only support constant output arrays, all the items must also
1284 : * be constant.
1285 : */
1286 276 : if (!IsA(value, Const))
1287 36 : return NULL;
1288 :
1289 240 : exprs = lappend(exprs, value);
1290 : }
1291 :
1292 : /* Finally, build ScalarArrayOpExpr at the top of the 'exprs' list. */
1293 84 : return make_SAOP_expr(opno, leftop, exprType(rightop),
1294 84 : linitial_oid(rte->colcollations), inputcollid,
1295 : exprs, false);
1296 : }
1297 :
1298 : /*
1299 : * convert_ANY_sublink_to_join: try to convert an ANY SubLink to a join
1300 : *
1301 : * The caller has found an ANY SubLink at the top level of one of the query's
1302 : * qual clauses, but has not checked the properties of the SubLink further.
1303 : * Decide whether it is appropriate to process this SubLink in join style.
1304 : * If so, form a JoinExpr and return it. Return NULL if the SubLink cannot
1305 : * be converted to a join.
1306 : *
1307 : * The only non-obvious input parameter is available_rels: this is the set
1308 : * of query rels that can safely be referenced in the sublink expression.
1309 : * (We must restrict this to avoid changing the semantics when a sublink
1310 : * is present in an outer join's ON qual.) The conversion must fail if
1311 : * the converted qual would reference any but these parent-query relids.
1312 : *
1313 : * On success, the returned JoinExpr has larg = NULL and rarg = the jointree
1314 : * item representing the pulled-up subquery. The caller must set larg to
1315 : * represent the relation(s) on the lefthand side of the new join, and insert
1316 : * the JoinExpr into the upper query's jointree at an appropriate place
1317 : * (typically, where the lefthand relation(s) had been). Note that the
1318 : * passed-in SubLink must also be removed from its original position in the
1319 : * query quals, since the quals of the returned JoinExpr replace it.
1320 : * (Notionally, we replace the SubLink with a constant TRUE, then elide the
1321 : * redundant constant from the qual.)
1322 : *
1323 : * On success, the caller is also responsible for recursively applying
1324 : * pull_up_sublinks processing to the rarg and quals of the returned JoinExpr.
1325 : * (On failure, there is no need to do anything, since pull_up_sublinks will
1326 : * be applied when we recursively plan the sub-select.)
1327 : *
1328 : * Side effects of a successful conversion include adding the SubLink's
1329 : * subselect to the query's rangetable, so that it can be referenced in
1330 : * the JoinExpr's rarg.
1331 : */
1332 : JoinExpr *
1333 4418 : convert_ANY_sublink_to_join(PlannerInfo *root, SubLink *sublink,
1334 : Relids available_rels)
1335 : {
1336 : JoinExpr *result;
1337 4418 : Query *parse = root->parse;
1338 4418 : Query *subselect = (Query *) sublink->subselect;
1339 : Relids upper_varnos;
1340 : int rtindex;
1341 : ParseNamespaceItem *nsitem;
1342 : RangeTblEntry *rte;
1343 : RangeTblRef *rtr;
1344 : List *subquery_vars;
1345 : Node *quals;
1346 : ParseState *pstate;
1347 : Relids sub_ref_outer_relids;
1348 : bool use_lateral;
1349 :
1350 : Assert(sublink->subLinkType == ANY_SUBLINK);
1351 :
1352 : /*
1353 : * If the sub-select contains any Vars of the parent query, we treat it as
1354 : * LATERAL. (Vars from higher levels don't matter here.)
1355 : */
1356 4418 : sub_ref_outer_relids = pull_varnos_of_level(NULL, (Node *) subselect, 1);
1357 4418 : use_lateral = !bms_is_empty(sub_ref_outer_relids);
1358 :
1359 : /*
1360 : * Can't convert if the sub-select contains parent-level Vars of relations
1361 : * not in available_rels.
1362 : */
1363 4418 : if (!bms_is_subset(sub_ref_outer_relids, available_rels))
1364 12 : return NULL;
1365 :
1366 : /*
1367 : * The test expression must contain some Vars of the parent query, else
1368 : * it's not gonna be a join. (Note that it won't have Vars referring to
1369 : * the subquery, rather Params.)
1370 : */
1371 4406 : upper_varnos = pull_varnos(root, sublink->testexpr);
1372 4406 : if (bms_is_empty(upper_varnos))
1373 12 : return NULL;
1374 :
1375 : /*
1376 : * However, it can't refer to anything outside available_rels.
1377 : */
1378 4394 : if (!bms_is_subset(upper_varnos, available_rels))
1379 24 : return NULL;
1380 :
1381 : /*
1382 : * The combining operators and left-hand expressions mustn't be volatile.
1383 : */
1384 4370 : if (contain_volatile_functions(sublink->testexpr))
1385 64 : return NULL;
1386 :
1387 : /* Create a dummy ParseState for addRangeTableEntryForSubquery */
1388 4306 : pstate = make_parsestate(NULL);
1389 :
1390 : /*
1391 : * Okay, pull up the sub-select into upper range table.
1392 : *
1393 : * We rely here on the assumption that the outer query has no references
1394 : * to the inner (necessarily true, other than the Vars that we build
1395 : * below). Therefore this is a lot easier than what pull_up_subqueries has
1396 : * to go through.
1397 : */
1398 4306 : nsitem = addRangeTableEntryForSubquery(pstate,
1399 : subselect,
1400 : makeAlias("ANY_subquery", NIL),
1401 : use_lateral,
1402 : false);
1403 4306 : rte = nsitem->p_rte;
1404 4306 : parse->rtable = lappend(parse->rtable, rte);
1405 4306 : rtindex = list_length(parse->rtable);
1406 :
1407 : /*
1408 : * Form a RangeTblRef for the pulled-up sub-select.
1409 : */
1410 4306 : rtr = makeNode(RangeTblRef);
1411 4306 : rtr->rtindex = rtindex;
1412 :
1413 : /*
1414 : * Build a list of Vars representing the subselect outputs.
1415 : */
1416 4306 : subquery_vars = generate_subquery_vars(root,
1417 : subselect->targetList,
1418 : rtindex);
1419 :
1420 : /*
1421 : * Build the new join's qual expression, replacing Params with these Vars.
1422 : */
1423 4306 : quals = convert_testexpr(root, sublink->testexpr, subquery_vars);
1424 :
1425 : /*
1426 : * And finally, build the JoinExpr node.
1427 : */
1428 4306 : result = makeNode(JoinExpr);
1429 4306 : result->jointype = JOIN_SEMI;
1430 4306 : result->isNatural = false;
1431 4306 : result->larg = NULL; /* caller must fill this in */
1432 4306 : result->rarg = (Node *) rtr;
1433 4306 : result->usingClause = NIL;
1434 4306 : result->join_using_alias = NULL;
1435 4306 : result->quals = quals;
1436 4306 : result->alias = NULL;
1437 4306 : result->rtindex = 0; /* we don't need an RTE for it */
1438 :
1439 4306 : return result;
1440 : }
1441 :
1442 : /*
1443 : * convert_EXISTS_sublink_to_join: try to convert an EXISTS SubLink to a join
1444 : *
1445 : * The API of this function is identical to convert_ANY_sublink_to_join's,
1446 : * except that we also support the case where the caller has found NOT EXISTS,
1447 : * so we need an additional input parameter "under_not".
1448 : */
1449 : JoinExpr *
1450 3814 : convert_EXISTS_sublink_to_join(PlannerInfo *root, SubLink *sublink,
1451 : bool under_not, Relids available_rels)
1452 : {
1453 : JoinExpr *result;
1454 3814 : Query *parse = root->parse;
1455 3814 : Query *subselect = (Query *) sublink->subselect;
1456 : Node *whereClause;
1457 : int rtoffset;
1458 : int varno;
1459 : Relids clause_varnos;
1460 : Relids upper_varnos;
1461 :
1462 : Assert(sublink->subLinkType == EXISTS_SUBLINK);
1463 :
1464 : /*
1465 : * Can't flatten if it contains WITH. (We could arrange to pull up the
1466 : * WITH into the parent query's cteList, but that risks changing the
1467 : * semantics, since a WITH ought to be executed once per associated query
1468 : * call.) Note that convert_ANY_sublink_to_join doesn't have to reject
1469 : * this case, since it just produces a subquery RTE that doesn't have to
1470 : * get flattened into the parent query.
1471 : */
1472 3814 : if (subselect->cteList)
1473 0 : return NULL;
1474 :
1475 : /*
1476 : * Copy the subquery so we can modify it safely (see comments in
1477 : * make_subplan).
1478 : */
1479 3814 : subselect = copyObject(subselect);
1480 :
1481 : /*
1482 : * See if the subquery can be simplified based on the knowledge that it's
1483 : * being used in EXISTS(). If we aren't able to get rid of its
1484 : * targetlist, we have to fail, because the pullup operation leaves us
1485 : * with noplace to evaluate the targetlist.
1486 : */
1487 3814 : if (!simplify_EXISTS_query(root, subselect))
1488 32 : return NULL;
1489 :
1490 : /*
1491 : * Separate out the WHERE clause. (We could theoretically also remove
1492 : * top-level plain JOIN/ON clauses, but it's probably not worth the
1493 : * trouble.)
1494 : */
1495 3782 : whereClause = subselect->jointree->quals;
1496 3782 : subselect->jointree->quals = NULL;
1497 :
1498 : /*
1499 : * The rest of the sub-select must not refer to any Vars of the parent
1500 : * query. (Vars of higher levels should be okay, though.)
1501 : */
1502 3782 : if (contain_vars_of_level((Node *) subselect, 1))
1503 0 : return NULL;
1504 :
1505 : /*
1506 : * On the other hand, the WHERE clause must contain some Vars of the
1507 : * parent query, else it's not gonna be a join.
1508 : */
1509 3782 : if (!contain_vars_of_level(whereClause, 1))
1510 98 : return NULL;
1511 :
1512 : /*
1513 : * We don't risk optimizing if the WHERE clause is volatile, either.
1514 : */
1515 3684 : if (contain_volatile_functions(whereClause))
1516 0 : return NULL;
1517 :
1518 : /*
1519 : * The subquery must have a nonempty jointree, but we can make it so.
1520 : */
1521 3684 : replace_empty_jointree(subselect);
1522 :
1523 : /*
1524 : * Prepare to pull up the sub-select into top range table.
1525 : *
1526 : * We rely here on the assumption that the outer query has no references
1527 : * to the inner (necessarily true). Therefore this is a lot easier than
1528 : * what pull_up_subqueries has to go through.
1529 : *
1530 : * In fact, it's even easier than what convert_ANY_sublink_to_join has to
1531 : * do. The machinations of simplify_EXISTS_query ensured that there is
1532 : * nothing interesting in the subquery except an rtable and jointree, and
1533 : * even the jointree FromExpr no longer has quals. So we can just append
1534 : * the rtable to our own and use the FromExpr in our jointree. But first,
1535 : * adjust all level-zero varnos in the subquery to account for the rtable
1536 : * merger.
1537 : */
1538 3684 : rtoffset = list_length(parse->rtable);
1539 3684 : OffsetVarNodes((Node *) subselect, rtoffset, 0);
1540 3684 : OffsetVarNodes(whereClause, rtoffset, 0);
1541 :
1542 : /*
1543 : * Upper-level vars in subquery will now be one level closer to their
1544 : * parent than before; in particular, anything that had been level 1
1545 : * becomes level zero.
1546 : */
1547 3684 : IncrementVarSublevelsUp((Node *) subselect, -1, 1);
1548 3684 : IncrementVarSublevelsUp(whereClause, -1, 1);
1549 :
1550 : /*
1551 : * Now that the WHERE clause is adjusted to match the parent query
1552 : * environment, we can easily identify all the level-zero rels it uses.
1553 : * The ones <= rtoffset belong to the upper query; the ones > rtoffset do
1554 : * not.
1555 : */
1556 3684 : clause_varnos = pull_varnos(root, whereClause);
1557 3684 : upper_varnos = NULL;
1558 3684 : varno = -1;
1559 11076 : while ((varno = bms_next_member(clause_varnos, varno)) >= 0)
1560 : {
1561 7392 : if (varno <= rtoffset)
1562 3708 : upper_varnos = bms_add_member(upper_varnos, varno);
1563 : }
1564 3684 : bms_free(clause_varnos);
1565 : Assert(!bms_is_empty(upper_varnos));
1566 :
1567 : /*
1568 : * Now that we've got the set of upper-level varnos, we can make the last
1569 : * check: only available_rels can be referenced.
1570 : */
1571 3684 : if (!bms_is_subset(upper_varnos, available_rels))
1572 32 : return NULL;
1573 :
1574 : /*
1575 : * Now we can attach the modified subquery rtable to the parent. This also
1576 : * adds subquery's RTEPermissionInfos into the upper query.
1577 : */
1578 3652 : CombineRangeTables(&parse->rtable, &parse->rteperminfos,
1579 : subselect->rtable, subselect->rteperminfos);
1580 :
1581 : /*
1582 : * And finally, build the JoinExpr node.
1583 : */
1584 3652 : result = makeNode(JoinExpr);
1585 3652 : result->jointype = under_not ? JOIN_ANTI : JOIN_SEMI;
1586 3652 : result->isNatural = false;
1587 3652 : result->larg = NULL; /* caller must fill this in */
1588 : /* flatten out the FromExpr node if it's useless */
1589 3652 : if (list_length(subselect->jointree->fromlist) == 1)
1590 3634 : result->rarg = (Node *) linitial(subselect->jointree->fromlist);
1591 : else
1592 18 : result->rarg = (Node *) subselect->jointree;
1593 3652 : result->usingClause = NIL;
1594 3652 : result->join_using_alias = NULL;
1595 3652 : result->quals = whereClause;
1596 3652 : result->alias = NULL;
1597 3652 : result->rtindex = 0; /* we don't need an RTE for it */
1598 :
1599 3652 : return result;
1600 : }
1601 :
1602 : /*
1603 : * simplify_EXISTS_query: remove any useless stuff in an EXISTS's subquery
1604 : *
1605 : * The only thing that matters about an EXISTS query is whether it returns
1606 : * zero or more than zero rows. Therefore, we can remove certain SQL features
1607 : * that won't affect that. The only part that is really likely to matter in
1608 : * typical usage is simplifying the targetlist: it's a common habit to write
1609 : * "SELECT * FROM" even though there is no need to evaluate any columns.
1610 : *
1611 : * Note: by suppressing the targetlist we could cause an observable behavioral
1612 : * change, namely that any errors that might occur in evaluating the tlist
1613 : * won't occur, nor will other side-effects of volatile functions. This seems
1614 : * unlikely to bother anyone in practice.
1615 : *
1616 : * Returns true if was able to discard the targetlist, else false.
1617 : */
1618 : static bool
1619 8774 : simplify_EXISTS_query(PlannerInfo *root, Query *query)
1620 : {
1621 : ListCell *lc;
1622 :
1623 : /*
1624 : * We don't try to simplify at all if the query uses set operations,
1625 : * aggregates, grouping sets, SRFs, modifying CTEs, HAVING, OFFSET, or FOR
1626 : * UPDATE/SHARE; none of these seem likely in normal usage and their
1627 : * possible effects are complex. (Note: we could ignore an "OFFSET 0"
1628 : * clause, but that traditionally is used as an optimization fence, so we
1629 : * don't.)
1630 : */
1631 8774 : if (query->commandType != CMD_SELECT ||
1632 8774 : query->setOperations ||
1633 8774 : query->hasAggs ||
1634 8774 : query->groupingSets ||
1635 8774 : query->hasWindowFuncs ||
1636 8774 : query->hasTargetSRFs ||
1637 8774 : query->hasModifyingCTE ||
1638 8774 : query->havingQual ||
1639 8774 : query->limitOffset ||
1640 8750 : query->rowMarks)
1641 52 : return false;
1642 :
1643 : /*
1644 : * LIMIT with a constant positive (or NULL) value doesn't affect the
1645 : * semantics of EXISTS, so let's ignore such clauses. This is worth doing
1646 : * because people accustomed to certain other DBMSes may be in the habit
1647 : * of writing EXISTS(SELECT ... LIMIT 1) as an optimization. If there's a
1648 : * LIMIT with anything else as argument, though, we can't simplify.
1649 : */
1650 8722 : if (query->limitCount)
1651 : {
1652 : /*
1653 : * The LIMIT clause has not yet been through eval_const_expressions,
1654 : * so we have to apply that here. It might seem like this is a waste
1655 : * of cycles, since the only case plausibly worth worrying about is
1656 : * "LIMIT 1" ... but what we'll actually see is "LIMIT int8(1::int4)",
1657 : * so we have to fold constants or we're not going to recognize it.
1658 : */
1659 24 : Node *node = eval_const_expressions(root, query->limitCount);
1660 : Const *limit;
1661 :
1662 : /* Might as well update the query if we simplified the clause. */
1663 24 : query->limitCount = node;
1664 :
1665 24 : if (!IsA(node, Const))
1666 0 : return false;
1667 :
1668 24 : limit = (Const *) node;
1669 : Assert(limit->consttype == INT8OID);
1670 24 : if (!limit->constisnull && DatumGetInt64(limit->constvalue) <= 0)
1671 12 : return false;
1672 :
1673 : /* Whether or not the targetlist is safe, we can drop the LIMIT. */
1674 12 : query->limitCount = NULL;
1675 : }
1676 :
1677 : /*
1678 : * Otherwise, we can throw away the targetlist, as well as any GROUP,
1679 : * WINDOW, DISTINCT, and ORDER BY clauses; none of those clauses will
1680 : * change a nonzero-rows result to zero rows or vice versa. (Furthermore,
1681 : * since our parsetree representation of these clauses depends on the
1682 : * targetlist, we'd better throw them away if we drop the targetlist.)
1683 : */
1684 8710 : query->targetList = NIL;
1685 8710 : query->groupClause = NIL;
1686 8710 : query->windowClause = NIL;
1687 8710 : query->distinctClause = NIL;
1688 8710 : query->sortClause = NIL;
1689 8710 : query->hasDistinctOn = false;
1690 :
1691 : /*
1692 : * Since we have thrown away the GROUP BY clauses, we'd better remove the
1693 : * RTE_GROUP RTE and clear the hasGroupRTE flag.
1694 : */
1695 17708 : foreach(lc, query->rtable)
1696 : {
1697 9004 : RangeTblEntry *rte = lfirst_node(RangeTblEntry, lc);
1698 :
1699 : /*
1700 : * Remove the RTE_GROUP RTE and clear the hasGroupRTE flag. (Since
1701 : * we'll exit the foreach loop immediately, we don't bother with
1702 : * foreach_delete_current.)
1703 : */
1704 9004 : if (rte->rtekind == RTE_GROUP)
1705 : {
1706 : Assert(query->hasGroupRTE);
1707 6 : query->rtable = list_delete_cell(query->rtable, lc);
1708 6 : query->hasGroupRTE = false;
1709 6 : break;
1710 : }
1711 : }
1712 :
1713 8710 : return true;
1714 : }
1715 :
1716 : /*
1717 : * convert_EXISTS_to_ANY: try to convert EXISTS to a hashable ANY sublink
1718 : *
1719 : * The subselect is expected to be a fresh copy that we can munge up,
1720 : * and to have been successfully passed through simplify_EXISTS_query.
1721 : *
1722 : * On success, the modified subselect is returned, and we store a suitable
1723 : * upper-level test expression at *testexpr, plus a list of the subselect's
1724 : * output Params at *paramIds. (The test expression is already Param-ified
1725 : * and hence need not go through convert_testexpr, which is why we have to
1726 : * deal with the Param IDs specially.)
1727 : *
1728 : * On failure, returns NULL.
1729 : */
1730 : static Query *
1731 2330 : convert_EXISTS_to_ANY(PlannerInfo *root, Query *subselect,
1732 : Node **testexpr, List **paramIds)
1733 : {
1734 : Node *whereClause;
1735 : List *leftargs,
1736 : *rightargs,
1737 : *opids,
1738 : *opcollations,
1739 : *newWhere,
1740 : *tlist,
1741 : *testlist,
1742 : *paramids;
1743 : ListCell *lc,
1744 : *rc,
1745 : *oc,
1746 : *cc;
1747 : AttrNumber resno;
1748 :
1749 : /*
1750 : * Query must not require a targetlist, since we have to insert a new one.
1751 : * Caller should have dealt with the case already.
1752 : */
1753 : Assert(subselect->targetList == NIL);
1754 :
1755 : /*
1756 : * Separate out the WHERE clause. (We could theoretically also remove
1757 : * top-level plain JOIN/ON clauses, but it's probably not worth the
1758 : * trouble.)
1759 : */
1760 2330 : whereClause = subselect->jointree->quals;
1761 2330 : subselect->jointree->quals = NULL;
1762 :
1763 : /*
1764 : * The rest of the sub-select must not refer to any Vars of the parent
1765 : * query. (Vars of higher levels should be okay, though.)
1766 : *
1767 : * Note: we need not check for Aggrefs separately because we know the
1768 : * sub-select is as yet unoptimized; any uplevel Aggref must therefore
1769 : * contain an uplevel Var reference. This is not the case below ...
1770 : */
1771 2330 : if (contain_vars_of_level((Node *) subselect, 1))
1772 6 : return NULL;
1773 :
1774 : /*
1775 : * We don't risk optimizing if the WHERE clause is volatile, either.
1776 : */
1777 2324 : if (contain_volatile_functions(whereClause))
1778 0 : return NULL;
1779 :
1780 : /*
1781 : * Clean up the WHERE clause by doing const-simplification etc on it.
1782 : * Aside from simplifying the processing we're about to do, this is
1783 : * important for being able to pull chunks of the WHERE clause up into the
1784 : * parent query. Since we are invoked partway through the parent's
1785 : * preprocess_expression() work, earlier steps of preprocess_expression()
1786 : * wouldn't get applied to the pulled-up stuff unless we do them here. For
1787 : * the parts of the WHERE clause that get put back into the child query,
1788 : * this work is partially duplicative, but it shouldn't hurt.
1789 : *
1790 : * Note: we do not run flatten_join_alias_vars. This is OK because any
1791 : * parent aliases were flattened already, and we're not going to pull any
1792 : * child Vars (of any description) into the parent.
1793 : *
1794 : * Note: passing the parent's root to eval_const_expressions is
1795 : * technically wrong, but we can get away with it since only the
1796 : * boundParams (if any) are used, and those would be the same in a
1797 : * subroot.
1798 : */
1799 2324 : whereClause = eval_const_expressions(root, whereClause);
1800 2324 : whereClause = (Node *) canonicalize_qual((Expr *) whereClause, false);
1801 2324 : whereClause = (Node *) make_ands_implicit((Expr *) whereClause);
1802 :
1803 : /*
1804 : * We now have a flattened implicit-AND list of clauses, which we try to
1805 : * break apart into "outervar = innervar" hash clauses. Anything that
1806 : * can't be broken apart just goes back into the newWhere list. Note that
1807 : * we aren't trying hard yet to ensure that we have only outer or only
1808 : * inner on each side; we'll check that if we get to the end.
1809 : */
1810 2324 : leftargs = rightargs = opids = opcollations = newWhere = NIL;
1811 9036 : foreach(lc, (List *) whereClause)
1812 : {
1813 6712 : OpExpr *expr = (OpExpr *) lfirst(lc);
1814 :
1815 11016 : if (IsA(expr, OpExpr) &&
1816 4304 : hash_ok_operator(expr))
1817 : {
1818 3222 : Node *leftarg = (Node *) linitial(expr->args);
1819 3222 : Node *rightarg = (Node *) lsecond(expr->args);
1820 :
1821 3222 : if (contain_vars_of_level(leftarg, 1))
1822 : {
1823 496 : leftargs = lappend(leftargs, leftarg);
1824 496 : rightargs = lappend(rightargs, rightarg);
1825 496 : opids = lappend_oid(opids, expr->opno);
1826 496 : opcollations = lappend_oid(opcollations, expr->inputcollid);
1827 496 : continue;
1828 : }
1829 2726 : if (contain_vars_of_level(rightarg, 1))
1830 : {
1831 : /*
1832 : * We must commute the clause to put the outer var on the
1833 : * left, because the hashing code in nodeSubplan.c expects
1834 : * that. This probably shouldn't ever fail, since hashable
1835 : * operators ought to have commutators, but be paranoid.
1836 : */
1837 2162 : expr->opno = get_commutator(expr->opno);
1838 2162 : if (OidIsValid(expr->opno) && hash_ok_operator(expr))
1839 : {
1840 2162 : leftargs = lappend(leftargs, rightarg);
1841 2162 : rightargs = lappend(rightargs, leftarg);
1842 2162 : opids = lappend_oid(opids, expr->opno);
1843 2162 : opcollations = lappend_oid(opcollations, expr->inputcollid);
1844 2162 : continue;
1845 : }
1846 : /* If no commutator, no chance to optimize the WHERE clause */
1847 0 : return NULL;
1848 : }
1849 : }
1850 : /* Couldn't handle it as a hash clause */
1851 4054 : newWhere = lappend(newWhere, expr);
1852 : }
1853 :
1854 : /*
1855 : * If we didn't find anything we could convert, fail.
1856 : */
1857 2324 : if (leftargs == NIL)
1858 466 : return NULL;
1859 :
1860 : /*
1861 : * There mustn't be any parent Vars or Aggs in the stuff that we intend to
1862 : * put back into the child query. Note: you might think we don't need to
1863 : * check for Aggs separately, because an uplevel Agg must contain an
1864 : * uplevel Var in its argument. But it is possible that the uplevel Var
1865 : * got optimized away by eval_const_expressions. Consider
1866 : *
1867 : * SUM(CASE WHEN false THEN uplevelvar ELSE 0 END)
1868 : */
1869 3626 : if (contain_vars_of_level((Node *) newWhere, 1) ||
1870 1768 : contain_vars_of_level((Node *) rightargs, 1))
1871 90 : return NULL;
1872 1810 : if (root->parse->hasAggs &&
1873 84 : (contain_aggs_of_level((Node *) newWhere, 1) ||
1874 42 : contain_aggs_of_level((Node *) rightargs, 1)))
1875 0 : return NULL;
1876 :
1877 : /*
1878 : * And there can't be any child Vars in the stuff we intend to pull up.
1879 : * (Note: we'd need to check for child Aggs too, except we know the child
1880 : * has no aggs at all because of simplify_EXISTS_query's check. The same
1881 : * goes for window functions.)
1882 : */
1883 1768 : if (contain_vars_of_level((Node *) leftargs, 0))
1884 0 : return NULL;
1885 :
1886 : /*
1887 : * Also reject sublinks in the stuff we intend to pull up. (It might be
1888 : * possible to support this, but doesn't seem worth the complication.)
1889 : */
1890 1768 : if (contain_subplans((Node *) leftargs))
1891 0 : return NULL;
1892 :
1893 : /*
1894 : * Okay, adjust the sublevelsup in the stuff we're pulling up.
1895 : */
1896 1768 : IncrementVarSublevelsUp((Node *) leftargs, -1, 1);
1897 :
1898 : /*
1899 : * Put back any child-level-only WHERE clauses.
1900 : */
1901 1768 : if (newWhere)
1902 1564 : subselect->jointree->quals = (Node *) make_ands_explicit(newWhere);
1903 :
1904 : /*
1905 : * Build a new targetlist for the child that emits the expressions we
1906 : * need. Concurrently, build a testexpr for the parent using Params to
1907 : * reference the child outputs. (Since we generate Params directly here,
1908 : * there will be no need to convert the testexpr in build_subplan.)
1909 : */
1910 1768 : tlist = testlist = paramids = NIL;
1911 1768 : resno = 1;
1912 4336 : forfour(lc, leftargs, rc, rightargs, oc, opids, cc, opcollations)
1913 : {
1914 2568 : Node *leftarg = (Node *) lfirst(lc);
1915 2568 : Node *rightarg = (Node *) lfirst(rc);
1916 2568 : Oid opid = lfirst_oid(oc);
1917 2568 : Oid opcollation = lfirst_oid(cc);
1918 : Param *param;
1919 :
1920 2568 : param = generate_new_exec_param(root,
1921 : exprType(rightarg),
1922 : exprTypmod(rightarg),
1923 : exprCollation(rightarg));
1924 2568 : tlist = lappend(tlist,
1925 2568 : makeTargetEntry((Expr *) rightarg,
1926 2568 : resno++,
1927 : NULL,
1928 : false));
1929 2568 : testlist = lappend(testlist,
1930 2568 : make_opclause(opid, BOOLOID, false,
1931 : (Expr *) leftarg, (Expr *) param,
1932 : InvalidOid, opcollation));
1933 2568 : paramids = lappend_int(paramids, param->paramid);
1934 : }
1935 :
1936 : /* Put everything where it should go, and we're done */
1937 1768 : subselect->targetList = tlist;
1938 1768 : *testexpr = (Node *) make_ands_explicit(testlist);
1939 1768 : *paramIds = paramids;
1940 :
1941 1768 : return subselect;
1942 : }
1943 :
1944 :
1945 : /*
1946 : * Replace correlation vars (uplevel vars) with Params.
1947 : *
1948 : * Uplevel PlaceHolderVars, aggregates, GROUPING() expressions,
1949 : * MergeSupportFuncs, and ReturningExprs are replaced, too.
1950 : *
1951 : * Note: it is critical that this runs immediately after SS_process_sublinks.
1952 : * Since we do not recurse into the arguments of uplevel PHVs and aggregates,
1953 : * they will get copied to the appropriate subplan args list in the parent
1954 : * query with uplevel vars not replaced by Params, but only adjusted in level
1955 : * (see replace_outer_placeholdervar and replace_outer_agg). That's exactly
1956 : * what we want for the vars of the parent level --- but if a PHV's or
1957 : * aggregate's argument contains any further-up variables, they have to be
1958 : * replaced with Params in their turn. That will happen when the parent level
1959 : * runs SS_replace_correlation_vars. Therefore it must do so after expanding
1960 : * its sublinks to subplans. And we don't want any steps in between, else
1961 : * those steps would never get applied to the argument expressions, either in
1962 : * the parent or the child level.
1963 : *
1964 : * Another fairly tricky thing going on here is the handling of SubLinks in
1965 : * the arguments of uplevel PHVs/aggregates. Those are not touched inside the
1966 : * intermediate query level, either. Instead, SS_process_sublinks recurses on
1967 : * them after copying the PHV or Aggref expression into the parent plan level
1968 : * (this is actually taken care of in build_subplan).
1969 : */
1970 : Node *
1971 161578 : SS_replace_correlation_vars(PlannerInfo *root, Node *expr)
1972 : {
1973 : /* No setup needed for tree walk, so away we go */
1974 161578 : return replace_correlation_vars_mutator(expr, root);
1975 : }
1976 :
1977 : static Node *
1978 1489016 : replace_correlation_vars_mutator(Node *node, PlannerInfo *root)
1979 : {
1980 1489016 : if (node == NULL)
1981 69490 : return NULL;
1982 1419526 : if (IsA(node, Var))
1983 : {
1984 386594 : if (((Var *) node)->varlevelsup > 0)
1985 55232 : return (Node *) replace_outer_var(root, (Var *) node);
1986 : }
1987 1364294 : if (IsA(node, PlaceHolderVar))
1988 : {
1989 84 : if (((PlaceHolderVar *) node)->phlevelsup > 0)
1990 42 : return (Node *) replace_outer_placeholdervar(root,
1991 : (PlaceHolderVar *) node);
1992 : }
1993 1364252 : if (IsA(node, Aggref))
1994 : {
1995 9044 : if (((Aggref *) node)->agglevelsup > 0)
1996 52 : return (Node *) replace_outer_agg(root, (Aggref *) node);
1997 : }
1998 1364200 : if (IsA(node, GroupingFunc))
1999 : {
2000 90 : if (((GroupingFunc *) node)->agglevelsup > 0)
2001 64 : return (Node *) replace_outer_grouping(root, (GroupingFunc *) node);
2002 : }
2003 1364136 : if (IsA(node, MergeSupportFunc))
2004 : {
2005 36 : if (root->parse->commandType != CMD_MERGE)
2006 6 : return (Node *) replace_outer_merge_support(root,
2007 : (MergeSupportFunc *) node);
2008 : }
2009 1364130 : if (IsA(node, ReturningExpr))
2010 : {
2011 18 : if (((ReturningExpr *) node)->retlevelsup > 0)
2012 18 : return (Node *) replace_outer_returning(root,
2013 : (ReturningExpr *) node);
2014 : }
2015 1364112 : return expression_tree_mutator(node, replace_correlation_vars_mutator, root);
2016 : }
2017 :
2018 : /*
2019 : * Expand SubLinks to SubPlans in the given expression.
2020 : *
2021 : * The isQual argument tells whether or not this expression is a WHERE/HAVING
2022 : * qualifier expression. If it is, any sublinks appearing at top level need
2023 : * not distinguish FALSE from UNKNOWN return values.
2024 : */
2025 : Node *
2026 108532 : SS_process_sublinks(PlannerInfo *root, Node *expr, bool isQual)
2027 : {
2028 : process_sublinks_context context;
2029 :
2030 108532 : context.root = root;
2031 108532 : context.isTopQual = isQual;
2032 108532 : return process_sublinks_mutator(expr, &context);
2033 : }
2034 :
2035 : static Node *
2036 1444834 : process_sublinks_mutator(Node *node, process_sublinks_context *context)
2037 : {
2038 : process_sublinks_context locContext;
2039 :
2040 1444834 : locContext.root = context->root;
2041 :
2042 1444834 : if (node == NULL)
2043 62196 : return NULL;
2044 1382638 : if (IsA(node, SubLink))
2045 : {
2046 41056 : SubLink *sublink = (SubLink *) node;
2047 : Node *testexpr;
2048 :
2049 : /*
2050 : * First, recursively process the lefthand-side expressions, if any.
2051 : * They're not top-level anymore.
2052 : */
2053 41056 : locContext.isTopQual = false;
2054 41056 : testexpr = process_sublinks_mutator(sublink->testexpr, &locContext);
2055 :
2056 : /*
2057 : * Now build the SubPlan node and make the expr to return.
2058 : */
2059 41056 : return make_subplan(context->root,
2060 41056 : (Query *) sublink->subselect,
2061 : sublink->subLinkType,
2062 : sublink->subLinkId,
2063 : testexpr,
2064 41056 : context->isTopQual);
2065 : }
2066 :
2067 : /*
2068 : * Don't recurse into the arguments of an outer PHV, Aggref, GroupingFunc,
2069 : * or ReturningExpr here. Any SubLinks in the arguments have to be dealt
2070 : * with at the outer query level; they'll be handled when build_subplan
2071 : * collects the PHV, Aggref, GroupingFunc, or ReturningExpr into the
2072 : * arguments to be passed down to the current subplan.
2073 : */
2074 1341582 : if (IsA(node, PlaceHolderVar))
2075 : {
2076 210 : if (((PlaceHolderVar *) node)->phlevelsup > 0)
2077 0 : return node;
2078 : }
2079 1341372 : else if (IsA(node, Aggref))
2080 : {
2081 584 : if (((Aggref *) node)->agglevelsup > 0)
2082 18 : return node;
2083 : }
2084 1340788 : else if (IsA(node, GroupingFunc))
2085 : {
2086 160 : if (((GroupingFunc *) node)->agglevelsup > 0)
2087 36 : return node;
2088 : }
2089 1340628 : else if (IsA(node, ReturningExpr))
2090 : {
2091 198 : if (((ReturningExpr *) node)->retlevelsup > 0)
2092 6 : return node;
2093 : }
2094 :
2095 : /*
2096 : * We should never see a SubPlan expression in the input (since this is
2097 : * the very routine that creates 'em to begin with). We shouldn't find
2098 : * ourselves invoked directly on a Query, either.
2099 : */
2100 : Assert(!IsA(node, SubPlan));
2101 : Assert(!IsA(node, AlternativeSubPlan));
2102 : Assert(!IsA(node, Query));
2103 :
2104 : /*
2105 : * Because make_subplan() could return an AND or OR clause, we have to
2106 : * take steps to preserve AND/OR flatness of a qual. We assume the input
2107 : * has been AND/OR flattened and so we need no recursion here.
2108 : *
2109 : * (Due to the coding here, we will not get called on the List subnodes of
2110 : * an AND; and the input is *not* yet in implicit-AND format. So no check
2111 : * is needed for a bare List.)
2112 : *
2113 : * Anywhere within the top-level AND/OR clause structure, we can tell
2114 : * make_subplan() that NULL and FALSE are interchangeable. So isTopQual
2115 : * propagates down in both cases. (Note that this is unlike the meaning
2116 : * of "top level qual" used in most other places in Postgres.)
2117 : */
2118 1341522 : if (is_andclause(node))
2119 : {
2120 20920 : List *newargs = NIL;
2121 : ListCell *l;
2122 :
2123 : /* Still at qual top-level */
2124 20920 : locContext.isTopQual = context->isTopQual;
2125 :
2126 76634 : foreach(l, ((BoolExpr *) node)->args)
2127 : {
2128 : Node *newarg;
2129 :
2130 55714 : newarg = process_sublinks_mutator(lfirst(l), &locContext);
2131 55714 : if (is_andclause(newarg))
2132 0 : newargs = list_concat(newargs, ((BoolExpr *) newarg)->args);
2133 : else
2134 55714 : newargs = lappend(newargs, newarg);
2135 : }
2136 20920 : return (Node *) make_andclause(newargs);
2137 : }
2138 :
2139 1320602 : if (is_orclause(node))
2140 : {
2141 2542 : List *newargs = NIL;
2142 : ListCell *l;
2143 :
2144 : /* Still at qual top-level */
2145 2542 : locContext.isTopQual = context->isTopQual;
2146 :
2147 9106 : foreach(l, ((BoolExpr *) node)->args)
2148 : {
2149 : Node *newarg;
2150 :
2151 6564 : newarg = process_sublinks_mutator(lfirst(l), &locContext);
2152 6564 : if (is_orclause(newarg))
2153 0 : newargs = list_concat(newargs, ((BoolExpr *) newarg)->args);
2154 : else
2155 6564 : newargs = lappend(newargs, newarg);
2156 : }
2157 2542 : return (Node *) make_orclause(newargs);
2158 : }
2159 :
2160 : /*
2161 : * If we recurse down through anything other than an AND or OR node, we
2162 : * are definitely not at top qual level anymore.
2163 : */
2164 1318060 : locContext.isTopQual = false;
2165 :
2166 1318060 : return expression_tree_mutator(node,
2167 : process_sublinks_mutator,
2168 : &locContext);
2169 : }
2170 :
2171 : /*
2172 : * SS_identify_outer_params - identify the Params available from outer levels
2173 : *
2174 : * This must be run after SS_replace_correlation_vars and SS_process_sublinks
2175 : * processing is complete in a given query level as well as all of its
2176 : * descendant levels (which means it's most practical to do it at the end of
2177 : * processing the query level). We compute the set of paramIds that outer
2178 : * levels will make available to this level+descendants, and record it in
2179 : * root->outer_params for use while computing extParam/allParam sets in final
2180 : * plan cleanup. (We can't just compute it then, because the upper levels'
2181 : * plan_params lists are transient and will be gone by then.)
2182 : */
2183 : void
2184 531596 : SS_identify_outer_params(PlannerInfo *root)
2185 : {
2186 : Bitmapset *outer_params;
2187 : PlannerInfo *proot;
2188 : ListCell *l;
2189 :
2190 : /*
2191 : * If no parameters have been assigned anywhere in the tree, we certainly
2192 : * don't need to do anything here.
2193 : */
2194 531596 : if (root->glob->paramExecTypes == NIL)
2195 354758 : return;
2196 :
2197 : /*
2198 : * Scan all query levels above this one to see which parameters are due to
2199 : * be available from them, either because lower query levels have
2200 : * requested them (via plan_params) or because they will be available from
2201 : * initPlans of those levels.
2202 : */
2203 176838 : outer_params = NULL;
2204 234918 : for (proot = root->parent_root; proot != NULL; proot = proot->parent_root)
2205 : {
2206 : /*
2207 : * Include ordinary Var/PHV/Aggref/GroupingFunc/ReturningExpr params.
2208 : */
2209 105904 : foreach(l, proot->plan_params)
2210 : {
2211 47824 : PlannerParamItem *pitem = (PlannerParamItem *) lfirst(l);
2212 :
2213 47824 : outer_params = bms_add_member(outer_params, pitem->paramId);
2214 : }
2215 : /* Include any outputs of outer-level initPlans */
2216 64258 : foreach(l, proot->init_plans)
2217 : {
2218 6178 : SubPlan *initsubplan = (SubPlan *) lfirst(l);
2219 : ListCell *l2;
2220 :
2221 12356 : foreach(l2, initsubplan->setParam)
2222 : {
2223 6178 : outer_params = bms_add_member(outer_params, lfirst_int(l2));
2224 : }
2225 : }
2226 : /* Include worktable ID, if a recursive query is being planned */
2227 58080 : if (proot->wt_param_id >= 0)
2228 3210 : outer_params = bms_add_member(outer_params, proot->wt_param_id);
2229 : }
2230 176838 : root->outer_params = outer_params;
2231 : }
2232 :
2233 : /*
2234 : * SS_charge_for_initplans - account for initplans in Path costs & parallelism
2235 : *
2236 : * If any initPlans have been created in the current query level, they will
2237 : * get attached to the Plan tree created from whichever Path we select from
2238 : * the given rel. Increment all that rel's Paths' costs to account for them,
2239 : * and if any of the initPlans are parallel-unsafe, mark all the rel's Paths
2240 : * parallel-unsafe as well.
2241 : *
2242 : * This is separate from SS_attach_initplans because we might conditionally
2243 : * create more initPlans during create_plan(), depending on which Path we
2244 : * select. However, Paths that would generate such initPlans are expected
2245 : * to have included their cost and parallel-safety effects already.
2246 : */
2247 : void
2248 531596 : SS_charge_for_initplans(PlannerInfo *root, RelOptInfo *final_rel)
2249 : {
2250 : Cost initplan_cost;
2251 : bool unsafe_initplans;
2252 : ListCell *lc;
2253 :
2254 : /* Nothing to do if no initPlans */
2255 531596 : if (root->init_plans == NIL)
2256 519636 : return;
2257 :
2258 : /*
2259 : * Compute the cost increment just once, since it will be the same for all
2260 : * Paths. Also check for parallel-unsafe initPlans.
2261 : */
2262 11960 : SS_compute_initplan_cost(root->init_plans,
2263 : &initplan_cost, &unsafe_initplans);
2264 :
2265 : /*
2266 : * Now adjust the costs and parallel_safe flags.
2267 : */
2268 24090 : foreach(lc, final_rel->pathlist)
2269 : {
2270 12130 : Path *path = (Path *) lfirst(lc);
2271 :
2272 12130 : path->startup_cost += initplan_cost;
2273 12130 : path->total_cost += initplan_cost;
2274 12130 : if (unsafe_initplans)
2275 6644 : path->parallel_safe = false;
2276 : }
2277 :
2278 : /*
2279 : * Adjust partial paths' costs too, or forget them entirely if we must
2280 : * consider the rel parallel-unsafe.
2281 : */
2282 11960 : if (unsafe_initplans)
2283 : {
2284 6568 : final_rel->partial_pathlist = NIL;
2285 6568 : final_rel->consider_parallel = false;
2286 : }
2287 : else
2288 : {
2289 5404 : foreach(lc, final_rel->partial_pathlist)
2290 : {
2291 12 : Path *path = (Path *) lfirst(lc);
2292 :
2293 12 : path->startup_cost += initplan_cost;
2294 12 : path->total_cost += initplan_cost;
2295 : }
2296 : }
2297 :
2298 : /* We needn't do set_cheapest() here, caller will do it */
2299 : }
2300 :
2301 : /*
2302 : * SS_compute_initplan_cost - count up the cost delta for some initplans
2303 : *
2304 : * The total cost returned in *initplan_cost_p should be added to both the
2305 : * startup and total costs of the plan node the initplans get attached to.
2306 : * We also report whether any of the initplans are not parallel-safe.
2307 : *
2308 : * The primary user of this is SS_charge_for_initplans, but it's also
2309 : * used in adjusting costs when we move initplans to another plan node.
2310 : */
2311 : void
2312 12198 : SS_compute_initplan_cost(List *init_plans,
2313 : Cost *initplan_cost_p,
2314 : bool *unsafe_initplans_p)
2315 : {
2316 : Cost initplan_cost;
2317 : bool unsafe_initplans;
2318 : ListCell *lc;
2319 :
2320 : /*
2321 : * We assume each initPlan gets run once during top plan startup. This is
2322 : * a conservative overestimate, since in fact an initPlan might be
2323 : * executed later than plan startup, or even not at all.
2324 : */
2325 12198 : initplan_cost = 0;
2326 12198 : unsafe_initplans = false;
2327 25386 : foreach(lc, init_plans)
2328 : {
2329 13188 : SubPlan *initsubplan = lfirst_node(SubPlan, lc);
2330 :
2331 13188 : initplan_cost += initsubplan->startup_cost + initsubplan->per_call_cost;
2332 13188 : if (!initsubplan->parallel_safe)
2333 7540 : unsafe_initplans = true;
2334 : }
2335 12198 : *initplan_cost_p = initplan_cost;
2336 12198 : *unsafe_initplans_p = unsafe_initplans;
2337 12198 : }
2338 :
2339 : /*
2340 : * SS_attach_initplans - attach initplans to topmost plan node
2341 : *
2342 : * Attach any initplans created in the current query level to the specified
2343 : * plan node, which should normally be the topmost node for the query level.
2344 : * (In principle the initPlans could go in any node at or above where they're
2345 : * referenced; but there seems no reason to put them any lower than the
2346 : * topmost node, so we don't bother to track exactly where they came from.)
2347 : *
2348 : * We do not touch the plan node's cost or parallel_safe flag. The initplans
2349 : * must have been accounted for in SS_charge_for_initplans, or by any later
2350 : * code that adds initplans via SS_make_initplan_from_plan.
2351 : */
2352 : void
2353 530332 : SS_attach_initplans(PlannerInfo *root, Plan *plan)
2354 : {
2355 530332 : plan->initPlan = root->init_plans;
2356 530332 : }
2357 :
2358 : /*
2359 : * SS_finalize_plan - do final parameter processing for a completed Plan.
2360 : *
2361 : * This recursively computes the extParam and allParam sets for every Plan
2362 : * node in the given plan tree. (Oh, and RangeTblFunction.funcparams too.)
2363 : *
2364 : * We assume that SS_finalize_plan has already been run on any initplans or
2365 : * subplans the plan tree could reference.
2366 : */
2367 : void
2368 203760 : SS_finalize_plan(PlannerInfo *root, Plan *plan)
2369 : {
2370 : /* No setup needed, just recurse through plan tree. */
2371 203760 : (void) finalize_plan(root, plan, -1, root->outer_params, NULL);
2372 203760 : }
2373 :
2374 : /*
2375 : * Recursive processing of all nodes in the plan tree
2376 : *
2377 : * gather_param is the rescan_param of an ancestral Gather/GatherMerge,
2378 : * or -1 if there is none.
2379 : *
2380 : * valid_params is the set of param IDs supplied by outer plan levels
2381 : * that are valid to reference in this plan node or its children.
2382 : *
2383 : * scan_params is a set of param IDs to force scan plan nodes to reference.
2384 : * This is for EvalPlanQual support, and is always NULL at the top of the
2385 : * recursion.
2386 : *
2387 : * The return value is the computed allParam set for the given Plan node.
2388 : * This is just an internal notational convenience: we can add a child
2389 : * plan's allParams to the set of param IDs of interest to this level
2390 : * in the same statement that recurses to that child.
2391 : *
2392 : * Do not scribble on caller's values of valid_params or scan_params!
2393 : *
2394 : * Note: although we attempt to deal with initPlans anywhere in the tree, the
2395 : * logic is not really right. The problem is that a plan node might return an
2396 : * output Param of its initPlan as a targetlist item, in which case it's valid
2397 : * for the parent plan level to reference that same Param; the parent's usage
2398 : * will be converted into a Var referencing the child plan node by setrefs.c.
2399 : * But this function would see the parent's reference as out of scope and
2400 : * complain about it. For now, this does not matter because the planner only
2401 : * attaches initPlans to the topmost plan node in a query level, so the case
2402 : * doesn't arise. If we ever merge this processing into setrefs.c, maybe it
2403 : * can be handled more cleanly.
2404 : */
2405 : static Bitmapset *
2406 1526564 : finalize_plan(PlannerInfo *root, Plan *plan,
2407 : int gather_param,
2408 : Bitmapset *valid_params,
2409 : Bitmapset *scan_params)
2410 : {
2411 : finalize_primnode_context context;
2412 : int locally_added_param;
2413 : Bitmapset *nestloop_params;
2414 : Bitmapset *initExtParam;
2415 : Bitmapset *initSetParam;
2416 : Bitmapset *child_params;
2417 : ListCell *l;
2418 :
2419 1526564 : if (plan == NULL)
2420 888178 : return NULL;
2421 :
2422 638386 : context.root = root;
2423 638386 : context.paramids = NULL; /* initialize set to empty */
2424 638386 : locally_added_param = -1; /* there isn't one */
2425 638386 : nestloop_params = NULL; /* there aren't any */
2426 :
2427 : /*
2428 : * Examine any initPlans to determine the set of external params they
2429 : * reference and the set of output params they supply. (We assume
2430 : * SS_finalize_plan was run on them already.)
2431 : */
2432 638386 : initExtParam = initSetParam = NULL;
2433 651914 : foreach(l, plan->initPlan)
2434 : {
2435 13528 : SubPlan *initsubplan = (SubPlan *) lfirst(l);
2436 13528 : Plan *initplan = planner_subplan_get_plan(root, initsubplan);
2437 : ListCell *l2;
2438 :
2439 13528 : initExtParam = bms_add_members(initExtParam, initplan->extParam);
2440 27104 : foreach(l2, initsubplan->setParam)
2441 : {
2442 13576 : initSetParam = bms_add_member(initSetParam, lfirst_int(l2));
2443 : }
2444 : }
2445 :
2446 : /* Any setParams are validly referenceable in this node and children */
2447 638386 : if (initSetParam)
2448 12312 : valid_params = bms_union(valid_params, initSetParam);
2449 :
2450 : /*
2451 : * When we call finalize_primnode, context.paramids sets are automatically
2452 : * merged together. But when recursing to self, we have to do it the hard
2453 : * way. We want the paramids set to include params in subplans as well as
2454 : * at this level.
2455 : */
2456 :
2457 : /* Find params in targetlist and qual */
2458 638386 : finalize_primnode((Node *) plan->targetlist, &context);
2459 638386 : finalize_primnode((Node *) plan->qual, &context);
2460 :
2461 : /*
2462 : * If it's a parallel-aware scan node, mark it as dependent on the parent
2463 : * Gather/GatherMerge's rescan Param.
2464 : */
2465 638386 : if (plan->parallel_aware)
2466 : {
2467 2520 : if (gather_param < 0)
2468 0 : elog(ERROR, "parallel-aware plan node is not below a Gather");
2469 2520 : context.paramids =
2470 2520 : bms_add_member(context.paramids, gather_param);
2471 : }
2472 :
2473 : /* Check additional node-type-specific fields */
2474 638386 : switch (nodeTag(plan))
2475 : {
2476 76988 : case T_Result:
2477 76988 : finalize_primnode(((Result *) plan)->resconstantqual,
2478 : &context);
2479 76988 : break;
2480 :
2481 94076 : case T_SeqScan:
2482 94076 : context.paramids = bms_add_members(context.paramids, scan_params);
2483 94076 : break;
2484 :
2485 104 : case T_SampleScan:
2486 104 : finalize_primnode((Node *) ((SampleScan *) plan)->tablesample,
2487 : &context);
2488 104 : context.paramids = bms_add_members(context.paramids, scan_params);
2489 104 : break;
2490 :
2491 98748 : case T_IndexScan:
2492 98748 : finalize_primnode((Node *) ((IndexScan *) plan)->indexqual,
2493 : &context);
2494 98748 : finalize_primnode((Node *) ((IndexScan *) plan)->indexorderby,
2495 : &context);
2496 :
2497 : /*
2498 : * we need not look at indexqualorig, since it will have the same
2499 : * param references as indexqual. Likewise, we can ignore
2500 : * indexorderbyorig.
2501 : */
2502 98748 : context.paramids = bms_add_members(context.paramids, scan_params);
2503 98748 : break;
2504 :
2505 7316 : case T_IndexOnlyScan:
2506 7316 : finalize_primnode((Node *) ((IndexOnlyScan *) plan)->indexqual,
2507 : &context);
2508 7316 : finalize_primnode((Node *) ((IndexOnlyScan *) plan)->recheckqual,
2509 : &context);
2510 7316 : finalize_primnode((Node *) ((IndexOnlyScan *) plan)->indexorderby,
2511 : &context);
2512 :
2513 : /*
2514 : * we need not look at indextlist, since it cannot contain Params.
2515 : */
2516 7316 : context.paramids = bms_add_members(context.paramids, scan_params);
2517 7316 : break;
2518 :
2519 9100 : case T_BitmapIndexScan:
2520 9100 : finalize_primnode((Node *) ((BitmapIndexScan *) plan)->indexqual,
2521 : &context);
2522 :
2523 : /*
2524 : * we need not look at indexqualorig, since it will have the same
2525 : * param references as indexqual.
2526 : */
2527 9100 : break;
2528 :
2529 8742 : case T_BitmapHeapScan:
2530 8742 : finalize_primnode((Node *) ((BitmapHeapScan *) plan)->bitmapqualorig,
2531 : &context);
2532 8742 : context.paramids = bms_add_members(context.paramids, scan_params);
2533 8742 : break;
2534 :
2535 604 : case T_TidScan:
2536 604 : finalize_primnode((Node *) ((TidScan *) plan)->tidquals,
2537 : &context);
2538 604 : context.paramids = bms_add_members(context.paramids, scan_params);
2539 604 : break;
2540 :
2541 34 : case T_TidRangeScan:
2542 34 : finalize_primnode((Node *) ((TidRangeScan *) plan)->tidrangequals,
2543 : &context);
2544 34 : context.paramids = bms_add_members(context.paramids, scan_params);
2545 34 : break;
2546 :
2547 19430 : case T_SubqueryScan:
2548 : {
2549 19430 : SubqueryScan *sscan = (SubqueryScan *) plan;
2550 : RelOptInfo *rel;
2551 : Bitmapset *subquery_params;
2552 :
2553 : /* We must run finalize_plan on the subquery */
2554 19430 : rel = find_base_rel(root, sscan->scan.scanrelid);
2555 19430 : subquery_params = rel->subroot->outer_params;
2556 19430 : if (gather_param >= 0)
2557 24 : subquery_params = bms_add_member(bms_copy(subquery_params),
2558 : gather_param);
2559 19430 : finalize_plan(rel->subroot, sscan->subplan, gather_param,
2560 : subquery_params, NULL);
2561 :
2562 : /* Now we can add its extParams to the parent's params */
2563 38860 : context.paramids = bms_add_members(context.paramids,
2564 19430 : sscan->subplan->extParam);
2565 : /* We need scan_params too, though */
2566 19430 : context.paramids = bms_add_members(context.paramids,
2567 : scan_params);
2568 : }
2569 19430 : break;
2570 :
2571 24580 : case T_FunctionScan:
2572 : {
2573 24580 : FunctionScan *fscan = (FunctionScan *) plan;
2574 : ListCell *lc;
2575 :
2576 : /*
2577 : * Call finalize_primnode independently on each function
2578 : * expression, so that we can record which params are
2579 : * referenced in each, in order to decide which need
2580 : * re-evaluating during rescan.
2581 : */
2582 49560 : foreach(lc, fscan->functions)
2583 : {
2584 24980 : RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc);
2585 : finalize_primnode_context funccontext;
2586 :
2587 24980 : funccontext = context;
2588 24980 : funccontext.paramids = NULL;
2589 :
2590 24980 : finalize_primnode(rtfunc->funcexpr, &funccontext);
2591 :
2592 : /* remember results for execution */
2593 24980 : rtfunc->funcparams = funccontext.paramids;
2594 :
2595 : /* add the function's params to the overall set */
2596 24980 : context.paramids = bms_add_members(context.paramids,
2597 24980 : funccontext.paramids);
2598 : }
2599 :
2600 24580 : context.paramids = bms_add_members(context.paramids,
2601 : scan_params);
2602 : }
2603 24580 : break;
2604 :
2605 234 : case T_TableFuncScan:
2606 234 : finalize_primnode((Node *) ((TableFuncScan *) plan)->tablefunc,
2607 : &context);
2608 234 : context.paramids = bms_add_members(context.paramids, scan_params);
2609 234 : break;
2610 :
2611 5732 : case T_ValuesScan:
2612 5732 : finalize_primnode((Node *) ((ValuesScan *) plan)->values_lists,
2613 : &context);
2614 5732 : context.paramids = bms_add_members(context.paramids, scan_params);
2615 5732 : break;
2616 :
2617 4082 : case T_CteScan:
2618 : {
2619 : /*
2620 : * You might think we should add the node's cteParam to
2621 : * paramids, but we shouldn't because that param is just a
2622 : * linkage mechanism for multiple CteScan nodes for the same
2623 : * CTE; it is never used for changed-param signaling. What we
2624 : * have to do instead is to find the referenced CTE plan and
2625 : * incorporate its external paramids, so that the correct
2626 : * things will happen if the CTE references outer-level
2627 : * variables. See test cases for bug #4902. (We assume
2628 : * SS_finalize_plan was run on the CTE plan already.)
2629 : */
2630 4082 : int plan_id = ((CteScan *) plan)->ctePlanId;
2631 : Plan *cteplan;
2632 :
2633 : /* so, do this ... */
2634 4082 : if (plan_id < 1 || plan_id > list_length(root->glob->subplans))
2635 0 : elog(ERROR, "could not find plan for CteScan referencing plan ID %d",
2636 : plan_id);
2637 4082 : cteplan = (Plan *) list_nth(root->glob->subplans, plan_id - 1);
2638 4082 : context.paramids =
2639 4082 : bms_add_members(context.paramids, cteplan->extParam);
2640 :
2641 : #ifdef NOT_USED
2642 : /* ... but not this */
2643 : context.paramids =
2644 : bms_add_member(context.paramids,
2645 : ((CteScan *) plan)->cteParam);
2646 : #endif
2647 :
2648 4082 : context.paramids = bms_add_members(context.paramids,
2649 : scan_params);
2650 : }
2651 4082 : break;
2652 :
2653 1004 : case T_WorkTableScan:
2654 1004 : context.paramids =
2655 1004 : bms_add_member(context.paramids,
2656 : ((WorkTableScan *) plan)->wtParam);
2657 1004 : context.paramids = bms_add_members(context.paramids, scan_params);
2658 1004 : break;
2659 :
2660 390 : case T_NamedTuplestoreScan:
2661 390 : context.paramids = bms_add_members(context.paramids, scan_params);
2662 390 : break;
2663 :
2664 788 : case T_ForeignScan:
2665 : {
2666 788 : ForeignScan *fscan = (ForeignScan *) plan;
2667 :
2668 788 : finalize_primnode((Node *) fscan->fdw_exprs,
2669 : &context);
2670 788 : finalize_primnode((Node *) fscan->fdw_recheck_quals,
2671 : &context);
2672 :
2673 : /* We assume fdw_scan_tlist cannot contain Params */
2674 788 : context.paramids = bms_add_members(context.paramids,
2675 : scan_params);
2676 : }
2677 788 : break;
2678 :
2679 0 : case T_CustomScan:
2680 : {
2681 0 : CustomScan *cscan = (CustomScan *) plan;
2682 : ListCell *lc;
2683 :
2684 0 : finalize_primnode((Node *) cscan->custom_exprs,
2685 : &context);
2686 : /* We assume custom_scan_tlist cannot contain Params */
2687 0 : context.paramids =
2688 0 : bms_add_members(context.paramids, scan_params);
2689 :
2690 : /* child nodes if any */
2691 0 : foreach(lc, cscan->custom_plans)
2692 : {
2693 0 : context.paramids =
2694 0 : bms_add_members(context.paramids,
2695 0 : finalize_plan(root,
2696 0 : (Plan *) lfirst(lc),
2697 : gather_param,
2698 : valid_params,
2699 : scan_params));
2700 : }
2701 : }
2702 0 : break;
2703 :
2704 92002 : case T_ModifyTable:
2705 : {
2706 92002 : ModifyTable *mtplan = (ModifyTable *) plan;
2707 :
2708 : /* Force descendant scan nodes to reference epqParam */
2709 92002 : locally_added_param = mtplan->epqParam;
2710 92002 : valid_params = bms_add_member(bms_copy(valid_params),
2711 : locally_added_param);
2712 92002 : scan_params = bms_add_member(bms_copy(scan_params),
2713 : locally_added_param);
2714 92002 : finalize_primnode((Node *) mtplan->returningLists,
2715 : &context);
2716 92002 : finalize_primnode((Node *) mtplan->onConflictSet,
2717 : &context);
2718 92002 : finalize_primnode((Node *) mtplan->onConflictWhere,
2719 : &context);
2720 : /* exclRelTlist contains only Vars, doesn't need examination */
2721 : }
2722 92002 : break;
2723 :
2724 10308 : case T_Append:
2725 : {
2726 35846 : foreach(l, ((Append *) plan)->appendplans)
2727 : {
2728 25538 : context.paramids =
2729 25538 : bms_add_members(context.paramids,
2730 25538 : finalize_plan(root,
2731 25538 : (Plan *) lfirst(l),
2732 : gather_param,
2733 : valid_params,
2734 : scan_params));
2735 : }
2736 : }
2737 10308 : break;
2738 :
2739 108 : case T_MergeAppend:
2740 : {
2741 456 : foreach(l, ((MergeAppend *) plan)->mergeplans)
2742 : {
2743 348 : context.paramids =
2744 348 : bms_add_members(context.paramids,
2745 348 : finalize_plan(root,
2746 348 : (Plan *) lfirst(l),
2747 : gather_param,
2748 : valid_params,
2749 : scan_params));
2750 : }
2751 : }
2752 108 : break;
2753 :
2754 154 : case T_BitmapAnd:
2755 : {
2756 462 : foreach(l, ((BitmapAnd *) plan)->bitmapplans)
2757 : {
2758 308 : context.paramids =
2759 308 : bms_add_members(context.paramids,
2760 308 : finalize_plan(root,
2761 308 : (Plan *) lfirst(l),
2762 : gather_param,
2763 : valid_params,
2764 : scan_params));
2765 : }
2766 : }
2767 154 : break;
2768 :
2769 204 : case T_BitmapOr:
2770 : {
2771 612 : foreach(l, ((BitmapOr *) plan)->bitmapplans)
2772 : {
2773 408 : context.paramids =
2774 408 : bms_add_members(context.paramids,
2775 408 : finalize_plan(root,
2776 408 : (Plan *) lfirst(l),
2777 : gather_param,
2778 : valid_params,
2779 : scan_params));
2780 : }
2781 : }
2782 204 : break;
2783 :
2784 68452 : case T_NestLoop:
2785 : {
2786 68452 : finalize_primnode((Node *) ((Join *) plan)->joinqual,
2787 : &context);
2788 : /* collect set of params that will be passed to right child */
2789 120548 : foreach(l, ((NestLoop *) plan)->nestParams)
2790 : {
2791 52096 : NestLoopParam *nlp = (NestLoopParam *) lfirst(l);
2792 :
2793 52096 : nestloop_params = bms_add_member(nestloop_params,
2794 : nlp->paramno);
2795 : }
2796 : }
2797 68452 : break;
2798 :
2799 4364 : case T_MergeJoin:
2800 4364 : finalize_primnode((Node *) ((Join *) plan)->joinqual,
2801 : &context);
2802 4364 : finalize_primnode((Node *) ((MergeJoin *) plan)->mergeclauses,
2803 : &context);
2804 4364 : break;
2805 :
2806 19712 : case T_HashJoin:
2807 19712 : finalize_primnode((Node *) ((Join *) plan)->joinqual,
2808 : &context);
2809 19712 : finalize_primnode((Node *) ((HashJoin *) plan)->hashclauses,
2810 : &context);
2811 19712 : break;
2812 :
2813 19712 : case T_Hash:
2814 19712 : finalize_primnode((Node *) ((Hash *) plan)->hashkeys,
2815 : &context);
2816 19712 : break;
2817 :
2818 2222 : case T_Limit:
2819 2222 : finalize_primnode(((Limit *) plan)->limitOffset,
2820 : &context);
2821 2222 : finalize_primnode(((Limit *) plan)->limitCount,
2822 : &context);
2823 2222 : break;
2824 :
2825 1004 : case T_RecursiveUnion:
2826 : /* child nodes are allowed to reference wtParam */
2827 1004 : locally_added_param = ((RecursiveUnion *) plan)->wtParam;
2828 1004 : valid_params = bms_add_member(bms_copy(valid_params),
2829 : locally_added_param);
2830 : /* wtParam does *not* get added to scan_params */
2831 1004 : break;
2832 :
2833 7532 : case T_LockRows:
2834 : /* Force descendant scan nodes to reference epqParam */
2835 7532 : locally_added_param = ((LockRows *) plan)->epqParam;
2836 7532 : valid_params = bms_add_member(bms_copy(valid_params),
2837 : locally_added_param);
2838 7532 : scan_params = bms_add_member(bms_copy(scan_params),
2839 : locally_added_param);
2840 7532 : break;
2841 :
2842 10638 : case T_Agg:
2843 : {
2844 10638 : Agg *agg = (Agg *) plan;
2845 :
2846 : /*
2847 : * AGG_HASHED plans need to know which Params are referenced
2848 : * in aggregate calls. Do a separate scan to identify them.
2849 : */
2850 10638 : if (agg->aggstrategy == AGG_HASHED)
2851 : {
2852 : finalize_primnode_context aggcontext;
2853 :
2854 1338 : aggcontext.root = root;
2855 1338 : aggcontext.paramids = NULL;
2856 1338 : finalize_agg_primnode((Node *) agg->plan.targetlist,
2857 : &aggcontext);
2858 1338 : finalize_agg_primnode((Node *) agg->plan.qual,
2859 : &aggcontext);
2860 1338 : agg->aggParams = aggcontext.paramids;
2861 : }
2862 : }
2863 10638 : break;
2864 :
2865 122 : case T_WindowAgg:
2866 122 : finalize_primnode(((WindowAgg *) plan)->startOffset,
2867 : &context);
2868 122 : finalize_primnode(((WindowAgg *) plan)->endOffset,
2869 : &context);
2870 122 : break;
2871 :
2872 954 : case T_Gather:
2873 : /* child nodes are allowed to reference rescan_param, if any */
2874 954 : locally_added_param = ((Gather *) plan)->rescan_param;
2875 954 : if (locally_added_param >= 0)
2876 : {
2877 948 : valid_params = bms_add_member(bms_copy(valid_params),
2878 : locally_added_param);
2879 :
2880 : /*
2881 : * We currently don't support nested Gathers. The issue so
2882 : * far as this function is concerned would be how to identify
2883 : * which child nodes depend on which Gather.
2884 : */
2885 : Assert(gather_param < 0);
2886 : /* Pass down rescan_param to child parallel-aware nodes */
2887 948 : gather_param = locally_added_param;
2888 : }
2889 : /* rescan_param does *not* get added to scan_params */
2890 954 : break;
2891 :
2892 330 : case T_GatherMerge:
2893 : /* child nodes are allowed to reference rescan_param, if any */
2894 330 : locally_added_param = ((GatherMerge *) plan)->rescan_param;
2895 330 : if (locally_added_param >= 0)
2896 : {
2897 330 : valid_params = bms_add_member(bms_copy(valid_params),
2898 : locally_added_param);
2899 :
2900 : /*
2901 : * We currently don't support nested Gathers. The issue so
2902 : * far as this function is concerned would be how to identify
2903 : * which child nodes depend on which Gather.
2904 : */
2905 : Assert(gather_param < 0);
2906 : /* Pass down rescan_param to child parallel-aware nodes */
2907 330 : gather_param = locally_added_param;
2908 : }
2909 : /* rescan_param does *not* get added to scan_params */
2910 330 : break;
2911 :
2912 1610 : case T_Memoize:
2913 1610 : finalize_primnode((Node *) ((Memoize *) plan)->param_exprs,
2914 : &context);
2915 1610 : break;
2916 :
2917 47006 : case T_ProjectSet:
2918 : case T_Material:
2919 : case T_Sort:
2920 : case T_IncrementalSort:
2921 : case T_Unique:
2922 : case T_SetOp:
2923 : case T_Group:
2924 : /* no node-type-specific fields need fixing */
2925 47006 : break;
2926 :
2927 0 : default:
2928 0 : elog(ERROR, "unrecognized node type: %d",
2929 : (int) nodeTag(plan));
2930 : }
2931 :
2932 : /* Process left and right child plans, if any */
2933 638386 : child_params = finalize_plan(root,
2934 638386 : plan->lefttree,
2935 : gather_param,
2936 : valid_params,
2937 : scan_params);
2938 638386 : context.paramids = bms_add_members(context.paramids, child_params);
2939 :
2940 638386 : if (nestloop_params)
2941 : {
2942 : /* right child can reference nestloop_params as well as valid_params */
2943 46618 : child_params = finalize_plan(root,
2944 46618 : plan->righttree,
2945 : gather_param,
2946 : bms_union(nestloop_params, valid_params),
2947 : scan_params);
2948 : /* ... and they don't count as parameters used at my level */
2949 46618 : child_params = bms_difference(child_params, nestloop_params);
2950 46618 : bms_free(nestloop_params);
2951 : }
2952 : else
2953 : {
2954 : /* easy case */
2955 591768 : child_params = finalize_plan(root,
2956 591768 : plan->righttree,
2957 : gather_param,
2958 : valid_params,
2959 : scan_params);
2960 : }
2961 638386 : context.paramids = bms_add_members(context.paramids, child_params);
2962 :
2963 : /*
2964 : * Any locally generated parameter doesn't count towards its generating
2965 : * plan node's external dependencies. (Note: if we changed valid_params
2966 : * and/or scan_params, we leak those bitmapsets; not worth the notational
2967 : * trouble to clean them up.)
2968 : */
2969 638386 : if (locally_added_param >= 0)
2970 : {
2971 101816 : context.paramids = bms_del_member(context.paramids,
2972 : locally_added_param);
2973 : }
2974 :
2975 : /* Now we have all the paramids referenced in this node and children */
2976 :
2977 638386 : if (!bms_is_subset(context.paramids, valid_params))
2978 0 : elog(ERROR, "plan should not reference subplan's variable");
2979 :
2980 : /*
2981 : * The plan node's allParam and extParam fields should include all its
2982 : * referenced paramids, plus contributions from any child initPlans.
2983 : * However, any setParams of the initPlans should not be present in the
2984 : * parent node's extParams, only in its allParams. (It's possible that
2985 : * some initPlans have extParams that are setParams of other initPlans.)
2986 : */
2987 :
2988 : /* allParam must include initplans' extParams and setParams */
2989 638386 : plan->allParam = bms_union(context.paramids, initExtParam);
2990 638386 : plan->allParam = bms_add_members(plan->allParam, initSetParam);
2991 : /* extParam must include any initplan extParams */
2992 638386 : plan->extParam = bms_union(context.paramids, initExtParam);
2993 : /* but not any initplan setParams */
2994 638386 : plan->extParam = bms_del_members(plan->extParam, initSetParam);
2995 :
2996 638386 : return plan->allParam;
2997 : }
2998 :
2999 : /*
3000 : * finalize_primnode: add IDs of all PARAM_EXEC params that appear (or will
3001 : * appear) in the given expression tree to the result set.
3002 : */
3003 : static bool
3004 10860702 : finalize_primnode(Node *node, finalize_primnode_context *context)
3005 : {
3006 10860702 : if (node == NULL)
3007 1284002 : return false;
3008 9576700 : if (IsA(node, Param))
3009 : {
3010 132082 : if (((Param *) node)->paramkind == PARAM_EXEC)
3011 : {
3012 129838 : int paramid = ((Param *) node)->paramid;
3013 :
3014 129838 : context->paramids = bms_add_member(context->paramids, paramid);
3015 : }
3016 132082 : return false; /* no more to do here */
3017 : }
3018 9444618 : else if (IsA(node, Aggref))
3019 : {
3020 : /*
3021 : * Check to see if the aggregate will be replaced by a Param
3022 : * referencing a subquery output during setrefs.c. If so, we must
3023 : * account for that Param here. (For various reasons, it's not
3024 : * convenient to perform that substitution earlier than setrefs.c, nor
3025 : * to perform this processing after setrefs.c. Thus we need a wart
3026 : * here.)
3027 : */
3028 13866 : Aggref *aggref = (Aggref *) node;
3029 : Param *aggparam;
3030 :
3031 13866 : aggparam = find_minmax_agg_replacement_param(context->root, aggref);
3032 13866 : if (aggparam != NULL)
3033 556 : context->paramids = bms_add_member(context->paramids,
3034 : aggparam->paramid);
3035 : /* Fall through to examine the agg's arguments */
3036 : }
3037 9430752 : else if (IsA(node, SubPlan))
3038 : {
3039 39804 : SubPlan *subplan = (SubPlan *) node;
3040 39804 : Plan *plan = planner_subplan_get_plan(context->root, subplan);
3041 : ListCell *lc;
3042 : Bitmapset *subparamids;
3043 :
3044 : /* Recurse into the testexpr, but not into the Plan */
3045 39804 : finalize_primnode(subplan->testexpr, context);
3046 :
3047 : /*
3048 : * Remove any param IDs of output parameters of the subplan that were
3049 : * referenced in the testexpr. These are not interesting for
3050 : * parameter change signaling since we always re-evaluate the subplan.
3051 : * Note that this wouldn't work too well if there might be uses of the
3052 : * same param IDs elsewhere in the plan, but that can't happen because
3053 : * generate_new_exec_param never tries to merge params.
3054 : */
3055 43086 : foreach(lc, subplan->paramIds)
3056 : {
3057 3282 : context->paramids = bms_del_member(context->paramids,
3058 : lfirst_int(lc));
3059 : }
3060 :
3061 : /* Also examine args list */
3062 39804 : finalize_primnode((Node *) subplan->args, context);
3063 :
3064 : /*
3065 : * Add params needed by the subplan to paramids, but excluding those
3066 : * we will pass down to it. (We assume SS_finalize_plan was run on
3067 : * the subplan already.)
3068 : */
3069 39804 : subparamids = bms_copy(plan->extParam);
3070 95198 : foreach(lc, subplan->parParam)
3071 : {
3072 55394 : subparamids = bms_del_member(subparamids, lfirst_int(lc));
3073 : }
3074 39804 : context->paramids = bms_join(context->paramids, subparamids);
3075 :
3076 39804 : return false; /* no more to do here */
3077 : }
3078 9404814 : return expression_tree_walker(node, finalize_primnode, context);
3079 : }
3080 :
3081 : /*
3082 : * finalize_agg_primnode: find all Aggref nodes in the given expression tree,
3083 : * and add IDs of all PARAM_EXEC params appearing within their aggregated
3084 : * arguments to the result set.
3085 : */
3086 : static bool
3087 10610 : finalize_agg_primnode(Node *node, finalize_primnode_context *context)
3088 : {
3089 10610 : if (node == NULL)
3090 1416 : return false;
3091 9194 : if (IsA(node, Aggref))
3092 : {
3093 1144 : Aggref *agg = (Aggref *) node;
3094 :
3095 : /* we should not consider the direct arguments, if any */
3096 1144 : finalize_primnode((Node *) agg->args, context);
3097 1144 : finalize_primnode((Node *) agg->aggfilter, context);
3098 1144 : return false; /* there can't be any Aggrefs below here */
3099 : }
3100 8050 : return expression_tree_walker(node, finalize_agg_primnode, context);
3101 : }
3102 :
3103 : /*
3104 : * SS_make_initplan_output_param - make a Param for an initPlan's output
3105 : *
3106 : * The plan is expected to return a scalar value of the given type/collation.
3107 : *
3108 : * Note that in some cases the initplan may not ever appear in the finished
3109 : * plan tree. If that happens, we'll have wasted a PARAM_EXEC slot, which
3110 : * is no big deal.
3111 : */
3112 : Param *
3113 446 : SS_make_initplan_output_param(PlannerInfo *root,
3114 : Oid resulttype, int32 resulttypmod,
3115 : Oid resultcollation)
3116 : {
3117 446 : return generate_new_exec_param(root, resulttype,
3118 : resulttypmod, resultcollation);
3119 : }
3120 :
3121 : /*
3122 : * SS_make_initplan_from_plan - given a plan tree, make it an InitPlan
3123 : *
3124 : * We build an EXPR_SUBLINK SubPlan node and put it into the initplan
3125 : * list for the outer query level. A Param that represents the initplan's
3126 : * output has already been assigned using SS_make_initplan_output_param.
3127 : */
3128 : void
3129 400 : SS_make_initplan_from_plan(PlannerInfo *root,
3130 : PlannerInfo *subroot, Plan *plan,
3131 : Param *prm)
3132 : {
3133 : SubPlan *node;
3134 :
3135 : /*
3136 : * Add the subplan and its PlannerInfo, as well as a dummy path entry, to
3137 : * the global lists. Ideally we'd save a real path, but right now our
3138 : * sole caller doesn't build a path that exactly matches the plan. Since
3139 : * we're not currently going to need the path for an initplan, it's not
3140 : * worth requiring construction of such a path.
3141 : */
3142 400 : root->glob->subplans = lappend(root->glob->subplans, plan);
3143 400 : root->glob->subpaths = lappend(root->glob->subpaths, NULL);
3144 400 : root->glob->subroots = lappend(root->glob->subroots, subroot);
3145 :
3146 : /*
3147 : * Create a SubPlan node and add it to the outer list of InitPlans. Note
3148 : * it has to appear after any other InitPlans it might depend on (see
3149 : * comments in ExecReScan).
3150 : */
3151 400 : node = makeNode(SubPlan);
3152 400 : node->subLinkType = EXPR_SUBLINK;
3153 400 : node->plan_id = list_length(root->glob->subplans);
3154 400 : node->plan_name = psprintf("InitPlan %d", node->plan_id);
3155 400 : get_first_col_type(plan, &node->firstColType, &node->firstColTypmod,
3156 : &node->firstColCollation);
3157 400 : node->parallel_safe = plan->parallel_safe;
3158 400 : node->setParam = list_make1_int(prm->paramid);
3159 :
3160 400 : root->init_plans = lappend(root->init_plans, node);
3161 :
3162 : /*
3163 : * The node can't have any inputs (since it's an initplan), so the
3164 : * parParam and args lists remain empty.
3165 : */
3166 :
3167 : /* Set costs of SubPlan using info from the plan tree */
3168 400 : cost_subplan(subroot, node, plan);
3169 400 : }
|