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