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