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