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