/src/postgres/src/backend/optimizer/prep/prepjointree.c
Line | Count | Source |
1 | | /*------------------------------------------------------------------------- |
2 | | * |
3 | | * prepjointree.c |
4 | | * Planner preprocessing for subqueries and join tree manipulation. |
5 | | * |
6 | | * NOTE: the intended sequence for invoking these operations is |
7 | | * preprocess_relation_rtes |
8 | | * replace_empty_jointree |
9 | | * pull_up_sublinks |
10 | | * preprocess_function_rtes |
11 | | * pull_up_subqueries |
12 | | * flatten_simple_union_all |
13 | | * do expression preprocessing (including flattening JOIN alias vars) |
14 | | * reduce_outer_joins |
15 | | * remove_useless_result_rtes |
16 | | * |
17 | | * |
18 | | * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group |
19 | | * Portions Copyright (c) 1994, Regents of the University of California |
20 | | * |
21 | | * |
22 | | * IDENTIFICATION |
23 | | * src/backend/optimizer/prep/prepjointree.c |
24 | | * |
25 | | *------------------------------------------------------------------------- |
26 | | */ |
27 | | #include "postgres.h" |
28 | | |
29 | | #include "access/table.h" |
30 | | #include "catalog/pg_type.h" |
31 | | #include "funcapi.h" |
32 | | #include "miscadmin.h" |
33 | | #include "nodes/makefuncs.h" |
34 | | #include "nodes/multibitmapset.h" |
35 | | #include "nodes/nodeFuncs.h" |
36 | | #include "optimizer/clauses.h" |
37 | | #include "optimizer/optimizer.h" |
38 | | #include "optimizer/placeholder.h" |
39 | | #include "optimizer/plancat.h" |
40 | | #include "optimizer/prep.h" |
41 | | #include "optimizer/subselect.h" |
42 | | #include "optimizer/tlist.h" |
43 | | #include "parser/parse_relation.h" |
44 | | #include "parser/parsetree.h" |
45 | | #include "rewrite/rewriteHandler.h" |
46 | | #include "rewrite/rewriteManip.h" |
47 | | #include "utils/rel.h" |
48 | | |
49 | | |
50 | | typedef struct nullingrel_info |
51 | | { |
52 | | /* |
53 | | * For each leaf RTE, nullingrels[rti] is the set of relids of outer joins |
54 | | * that potentially null that RTE. |
55 | | */ |
56 | | Relids *nullingrels; |
57 | | /* Length of range table (maximum index in nullingrels[]) */ |
58 | | int rtlength; /* used only for assertion checks */ |
59 | | } nullingrel_info; |
60 | | |
61 | | /* Options for wrapping an expression for identification purposes */ |
62 | | typedef enum ReplaceWrapOption |
63 | | { |
64 | | REPLACE_WRAP_NONE, /* no expressions need to be wrapped */ |
65 | | REPLACE_WRAP_ALL, /* all expressions need to be wrapped */ |
66 | | REPLACE_WRAP_VARFREE, /* variable-free expressions need to be |
67 | | * wrapped */ |
68 | | } ReplaceWrapOption; |
69 | | |
70 | | typedef struct pullup_replace_vars_context |
71 | | { |
72 | | PlannerInfo *root; |
73 | | List *targetlist; /* tlist of subquery being pulled up */ |
74 | | RangeTblEntry *target_rte; /* RTE of subquery */ |
75 | | int result_relation; /* the index of the result relation in the |
76 | | * rewritten query */ |
77 | | Relids relids; /* relids within subquery, as numbered after |
78 | | * pullup (set only if target_rte->lateral) */ |
79 | | nullingrel_info *nullinfo; /* per-RTE nullingrel info (set only if |
80 | | * target_rte->lateral) */ |
81 | | bool *outer_hasSubLinks; /* -> outer query's hasSubLinks */ |
82 | | int varno; /* varno of subquery */ |
83 | | ReplaceWrapOption wrap_option; /* do we need certain outputs to be PHVs? */ |
84 | | Node **rv_cache; /* cache for results with PHVs */ |
85 | | } pullup_replace_vars_context; |
86 | | |
87 | | typedef struct reduce_outer_joins_pass1_state |
88 | | { |
89 | | Relids relids; /* base relids within this subtree */ |
90 | | bool contains_outer; /* does subtree contain outer join(s)? */ |
91 | | Relids nullable_rels; /* base relids that are nullable within this |
92 | | * subtree */ |
93 | | Node *jtnode; /* the jointree node this state describes */ |
94 | | List *sub_states; /* List of states for subtree components */ |
95 | | } reduce_outer_joins_pass1_state; |
96 | | |
97 | | typedef struct reduce_outer_joins_pass2_state |
98 | | { |
99 | | Relids inner_reduced; /* OJ relids reduced to plain inner joins */ |
100 | | List *partial_reduced; /* List of partially reduced FULL joins */ |
101 | | Relids anti_reduced; /* OJ relids reduced to antijoins */ |
102 | | } reduce_outer_joins_pass2_state; |
103 | | |
104 | | typedef struct reduce_outer_joins_partial_state |
105 | | { |
106 | | int full_join_rti; /* RT index of a formerly-FULL join */ |
107 | | Relids unreduced_side; /* relids in its still-nullable side */ |
108 | | } reduce_outer_joins_partial_state; |
109 | | |
110 | | static Query *expand_virtual_generated_columns(PlannerInfo *root, Query *parse, |
111 | | RangeTblEntry *rte, int rt_index, |
112 | | Relation relation); |
113 | | static Node *pull_up_sublinks_jointree_recurse(PlannerInfo *root, Node *jtnode, |
114 | | Relids *relids); |
115 | | static Node *pull_up_sublinks_qual_recurse(PlannerInfo *root, Node *node, |
116 | | Node **jtlink1, Relids available_rels1, |
117 | | Node **jtlink2, Relids available_rels2); |
118 | | static Node *pull_up_subqueries_recurse(PlannerInfo *root, Node *jtnode, |
119 | | JoinExpr *lowest_outer_join, |
120 | | AppendRelInfo *containing_appendrel); |
121 | | static Node *pull_up_simple_subquery(PlannerInfo *root, Node *jtnode, |
122 | | RangeTblEntry *rte, |
123 | | JoinExpr *lowest_outer_join, |
124 | | AppendRelInfo *containing_appendrel); |
125 | | static Node *pull_up_simple_union_all(PlannerInfo *root, Node *jtnode, |
126 | | RangeTblEntry *rte); |
127 | | static void pull_up_union_leaf_queries(Node *setOp, PlannerInfo *root, |
128 | | int parentRTindex, Query *setOpQuery, |
129 | | int childRToffset); |
130 | | static void make_setop_translation_list(Query *query, int newvarno, |
131 | | AppendRelInfo *appinfo); |
132 | | static bool is_simple_subquery(PlannerInfo *root, Query *subquery, |
133 | | RangeTblEntry *rte, |
134 | | JoinExpr *lowest_outer_join); |
135 | | static Node *pull_up_simple_values(PlannerInfo *root, Node *jtnode, |
136 | | RangeTblEntry *rte); |
137 | | static bool is_simple_values(PlannerInfo *root, RangeTblEntry *rte); |
138 | | static Node *pull_up_constant_function(PlannerInfo *root, Node *jtnode, |
139 | | RangeTblEntry *rte, |
140 | | AppendRelInfo *containing_appendrel); |
141 | | static bool is_simple_union_all(Query *subquery); |
142 | | static bool is_simple_union_all_recurse(Node *setOp, Query *setOpQuery, |
143 | | List *colTypes); |
144 | | static bool is_safe_append_member(Query *subquery); |
145 | | static bool jointree_contains_lateral_outer_refs(PlannerInfo *root, |
146 | | Node *jtnode, bool restricted, |
147 | | Relids safe_upper_varnos); |
148 | | static void flatten_join_alias_vars_in_jointree(PlannerInfo *root, |
149 | | Node *jtnode); |
150 | | static void perform_pullup_replace_vars(PlannerInfo *root, |
151 | | pullup_replace_vars_context *rvcontext, |
152 | | AppendRelInfo *containing_appendrel); |
153 | | static void replace_vars_in_jointree(Node *jtnode, |
154 | | pullup_replace_vars_context *context); |
155 | | static Node *pullup_replace_vars(Node *expr, |
156 | | pullup_replace_vars_context *context); |
157 | | static Node *pullup_replace_vars_callback(const Var *var, |
158 | | replace_rte_variables_context *context); |
159 | | static Query *pullup_replace_vars_subquery(Query *query, |
160 | | pullup_replace_vars_context *context); |
161 | | static reduce_outer_joins_pass1_state *reduce_outer_joins_pass1(Node *jtnode); |
162 | | static void reduce_outer_joins_pass2(Node *jtnode, |
163 | | reduce_outer_joins_pass1_state *state1, |
164 | | reduce_outer_joins_pass2_state *state2, |
165 | | PlannerInfo *root, |
166 | | Relids nonnullable_rels, |
167 | | List *forced_null_vars); |
168 | | static void report_reduced_full_join(reduce_outer_joins_pass2_state *state2, |
169 | | int rtindex, Relids relids); |
170 | | static void remove_redundant_nullability_quals(Node *jtnode, |
171 | | Relids antijoins); |
172 | | static Node *strip_redundant_nullability_quals(Node *quals, Relids antijoins); |
173 | | static bool forced_null_var_is_attnotnull(PlannerInfo *root, |
174 | | List *forced_null_vars, |
175 | | reduce_outer_joins_pass1_state *state); |
176 | | static bool forced_null_var_is_nonnullable(PlannerInfo *root, |
177 | | List *forced_null_vars, |
178 | | reduce_outer_joins_pass1_state *state, |
179 | | List *extra_quals); |
180 | | static Node *remove_useless_results_recurse(PlannerInfo *root, Node *jtnode, |
181 | | Relids baserels, |
182 | | Node **parent_quals, |
183 | | Relids *dropped_outer_joins); |
184 | | static int get_result_relid(PlannerInfo *root, Node *jtnode); |
185 | | static void remove_result_refs(PlannerInfo *root, int varno, Node *newjtloc); |
186 | | static bool find_dependent_phvs(PlannerInfo *root, int varno, Relids baserels); |
187 | | static bool find_dependent_phvs_in_jointree(PlannerInfo *root, |
188 | | Node *node, int varno, |
189 | | Relids baserels); |
190 | | static void substitute_phv_relids(Node *node, |
191 | | int varno, Relids subrelids); |
192 | | static void fix_append_rel_relids(PlannerInfo *root, int varno, |
193 | | Relids subrelids); |
194 | | static Node *find_jointree_node_for_rel(Node *jtnode, int relid); |
195 | | static nullingrel_info *get_nullingrels(Query *parse); |
196 | | static void get_nullingrels_recurse(Node *jtnode, Relids upper_nullingrels, |
197 | | nullingrel_info *info); |
198 | | |
199 | | |
200 | | /* |
201 | | * transform_MERGE_to_join |
202 | | * Replace a MERGE's jointree to also include the target relation. |
203 | | */ |
204 | | void |
205 | | transform_MERGE_to_join(Query *parse) |
206 | 0 | { |
207 | 0 | RangeTblEntry *joinrte; |
208 | 0 | JoinExpr *joinexpr; |
209 | 0 | bool have_action[NUM_MERGE_MATCH_KINDS]; |
210 | 0 | JoinType jointype; |
211 | 0 | int joinrti; |
212 | 0 | List *vars; |
213 | 0 | RangeTblRef *rtr; |
214 | 0 | FromExpr *target; |
215 | 0 | Node *source; |
216 | 0 | int sourcerti; |
217 | |
|
218 | 0 | if (parse->commandType != CMD_MERGE) |
219 | 0 | return; |
220 | | |
221 | | /* XXX probably bogus */ |
222 | 0 | vars = NIL; |
223 | | |
224 | | /* |
225 | | * Work out what kind of join is required. If there any WHEN NOT MATCHED |
226 | | * BY SOURCE/TARGET actions, an outer join is required so that we process |
227 | | * all unmatched tuples from the source and/or target relations. |
228 | | * Otherwise, we can use an inner join. |
229 | | */ |
230 | 0 | have_action[MERGE_WHEN_MATCHED] = false; |
231 | 0 | have_action[MERGE_WHEN_NOT_MATCHED_BY_SOURCE] = false; |
232 | 0 | have_action[MERGE_WHEN_NOT_MATCHED_BY_TARGET] = false; |
233 | |
|
234 | 0 | foreach_node(MergeAction, action, parse->mergeActionList) |
235 | 0 | { |
236 | 0 | if (action->commandType != CMD_NOTHING) |
237 | 0 | have_action[action->matchKind] = true; |
238 | 0 | } |
239 | |
|
240 | 0 | if (have_action[MERGE_WHEN_NOT_MATCHED_BY_SOURCE] && |
241 | 0 | have_action[MERGE_WHEN_NOT_MATCHED_BY_TARGET]) |
242 | 0 | jointype = JOIN_FULL; |
243 | 0 | else if (have_action[MERGE_WHEN_NOT_MATCHED_BY_SOURCE]) |
244 | 0 | jointype = JOIN_LEFT; |
245 | 0 | else if (have_action[MERGE_WHEN_NOT_MATCHED_BY_TARGET]) |
246 | 0 | jointype = JOIN_RIGHT; |
247 | 0 | else |
248 | 0 | jointype = JOIN_INNER; |
249 | | |
250 | | /* Manufacture a join RTE to use. */ |
251 | 0 | joinrte = makeNode(RangeTblEntry); |
252 | 0 | joinrte->rtekind = RTE_JOIN; |
253 | 0 | joinrte->jointype = jointype; |
254 | 0 | joinrte->joinmergedcols = 0; |
255 | 0 | joinrte->joinaliasvars = vars; |
256 | 0 | joinrte->joinleftcols = NIL; /* MERGE does not allow JOIN USING */ |
257 | 0 | joinrte->joinrightcols = NIL; /* ditto */ |
258 | 0 | joinrte->join_using_alias = NULL; |
259 | |
|
260 | 0 | joinrte->alias = NULL; |
261 | 0 | joinrte->eref = makeAlias("*MERGE*", NIL); |
262 | 0 | joinrte->lateral = false; |
263 | 0 | joinrte->inh = false; |
264 | 0 | joinrte->inFromCl = true; |
265 | | |
266 | | /* |
267 | | * Add completed RTE to pstate's range table list, so that we know its |
268 | | * index. |
269 | | */ |
270 | 0 | parse->rtable = lappend(parse->rtable, joinrte); |
271 | 0 | joinrti = list_length(parse->rtable); |
272 | | |
273 | | /* |
274 | | * Create a JOIN between the target and the source relation. |
275 | | * |
276 | | * Here the target is identified by parse->mergeTargetRelation. For a |
277 | | * regular table, this will equal parse->resultRelation, but for a |
278 | | * trigger-updatable view, it will be the expanded view subquery that we |
279 | | * need to pull data from. |
280 | | * |
281 | | * The source relation is in parse->jointree->fromlist, but any quals in |
282 | | * parse->jointree->quals are restrictions on the target relation (if the |
283 | | * target relation is an auto-updatable view). |
284 | | */ |
285 | | /* target rel, with any quals */ |
286 | 0 | rtr = makeNode(RangeTblRef); |
287 | 0 | rtr->rtindex = parse->mergeTargetRelation; |
288 | 0 | target = makeFromExpr(list_make1(rtr), parse->jointree->quals); |
289 | | |
290 | | /* source rel (expect exactly one -- see transformMergeStmt()) */ |
291 | 0 | Assert(list_length(parse->jointree->fromlist) == 1); |
292 | 0 | source = linitial(parse->jointree->fromlist); |
293 | | |
294 | | /* |
295 | | * index of source rel (expect either a RangeTblRef or a JoinExpr -- see |
296 | | * transformFromClauseItem()). |
297 | | */ |
298 | 0 | if (IsA(source, RangeTblRef)) |
299 | 0 | sourcerti = ((RangeTblRef *) source)->rtindex; |
300 | 0 | else if (IsA(source, JoinExpr)) |
301 | 0 | sourcerti = ((JoinExpr *) source)->rtindex; |
302 | 0 | else |
303 | 0 | { |
304 | 0 | elog(ERROR, "unrecognized source node type: %d", |
305 | 0 | (int) nodeTag(source)); |
306 | 0 | sourcerti = 0; /* keep compiler quiet */ |
307 | 0 | } |
308 | | |
309 | | /* Join the source and target */ |
310 | 0 | joinexpr = makeNode(JoinExpr); |
311 | 0 | joinexpr->jointype = jointype; |
312 | 0 | joinexpr->isNatural = false; |
313 | 0 | joinexpr->larg = (Node *) target; |
314 | 0 | joinexpr->rarg = source; |
315 | 0 | joinexpr->usingClause = NIL; |
316 | 0 | joinexpr->join_using_alias = NULL; |
317 | 0 | joinexpr->quals = parse->mergeJoinCondition; |
318 | 0 | joinexpr->alias = NULL; |
319 | 0 | joinexpr->rtindex = joinrti; |
320 | | |
321 | | /* Make the new join be the sole entry in the query's jointree */ |
322 | 0 | parse->jointree->fromlist = list_make1(joinexpr); |
323 | 0 | parse->jointree->quals = NULL; |
324 | | |
325 | | /* |
326 | | * If necessary, mark parse->targetlist entries that refer to the target |
327 | | * as nullable by the join. Normally the targetlist will be empty for a |
328 | | * MERGE, but if the target is a trigger-updatable view, it will contain a |
329 | | * whole-row Var referring to the expanded view query. |
330 | | */ |
331 | 0 | if (parse->targetList != NIL && |
332 | 0 | (jointype == JOIN_RIGHT || jointype == JOIN_FULL)) |
333 | 0 | parse->targetList = (List *) |
334 | 0 | add_nulling_relids((Node *) parse->targetList, |
335 | 0 | bms_make_singleton(parse->mergeTargetRelation), |
336 | 0 | bms_make_singleton(joinrti)); |
337 | | |
338 | | /* |
339 | | * If the source relation is on the outer side of the join, mark any |
340 | | * source relation Vars in the join condition, actions, and RETURNING list |
341 | | * as nullable by the join. These Vars will be added to the targetlist by |
342 | | * preprocess_targetlist(), so it's important to mark them correctly here. |
343 | | * |
344 | | * It might seem that this is not necessary for Vars in the join |
345 | | * condition, since it is inside the join, but it is also needed above the |
346 | | * join (in the ModifyTable node) to distinguish between the MATCHED and |
347 | | * NOT MATCHED BY SOURCE cases -- see ExecMergeMatched(). Note that this |
348 | | * creates a modified copy of the join condition, for use above the join, |
349 | | * without modifying the original join condition, inside the join. |
350 | | */ |
351 | 0 | if (jointype == JOIN_LEFT || jointype == JOIN_FULL) |
352 | 0 | { |
353 | 0 | parse->mergeJoinCondition = |
354 | 0 | add_nulling_relids(parse->mergeJoinCondition, |
355 | 0 | bms_make_singleton(sourcerti), |
356 | 0 | bms_make_singleton(joinrti)); |
357 | |
|
358 | 0 | foreach_node(MergeAction, action, parse->mergeActionList) |
359 | 0 | { |
360 | 0 | action->qual = |
361 | 0 | add_nulling_relids(action->qual, |
362 | 0 | bms_make_singleton(sourcerti), |
363 | 0 | bms_make_singleton(joinrti)); |
364 | |
|
365 | 0 | action->targetList = (List *) |
366 | 0 | add_nulling_relids((Node *) action->targetList, |
367 | 0 | bms_make_singleton(sourcerti), |
368 | 0 | bms_make_singleton(joinrti)); |
369 | 0 | } |
370 | |
|
371 | 0 | parse->returningList = (List *) |
372 | 0 | add_nulling_relids((Node *) parse->returningList, |
373 | 0 | bms_make_singleton(sourcerti), |
374 | 0 | bms_make_singleton(joinrti)); |
375 | 0 | } |
376 | | |
377 | | /* |
378 | | * If there are any WHEN NOT MATCHED BY SOURCE actions, the executor will |
379 | | * use the join condition to distinguish between MATCHED and NOT MATCHED |
380 | | * BY SOURCE cases. Otherwise, it's no longer needed, and we set it to |
381 | | * NULL, saving cycles during planning and execution. |
382 | | * |
383 | | * We need to be careful though: the executor evaluates this condition |
384 | | * using the output of the join subplan node, which nulls the output from |
385 | | * the source relation when the join condition doesn't match. That risks |
386 | | * producing incorrect results when rechecking using a "non-strict" join |
387 | | * condition, such as "src.col IS NOT DISTINCT FROM tgt.col". To guard |
388 | | * against that, we add an additional "src IS NOT NULL" check to the join |
389 | | * condition, so that it does the right thing when performing a recheck |
390 | | * based on the output of the join subplan. |
391 | | */ |
392 | 0 | if (have_action[MERGE_WHEN_NOT_MATCHED_BY_SOURCE]) |
393 | 0 | { |
394 | 0 | Var *var; |
395 | 0 | NullTest *ntest; |
396 | | |
397 | | /* source wholerow Var (nullable by the new join) */ |
398 | 0 | var = makeWholeRowVar(rt_fetch(sourcerti, parse->rtable), |
399 | 0 | sourcerti, 0, false); |
400 | 0 | var->varnullingrels = bms_make_singleton(joinrti); |
401 | | |
402 | | /* "src IS NOT NULL" check */ |
403 | 0 | ntest = makeNode(NullTest); |
404 | 0 | ntest->arg = (Expr *) var; |
405 | 0 | ntest->nulltesttype = IS_NOT_NULL; |
406 | 0 | ntest->argisrow = false; |
407 | 0 | ntest->location = -1; |
408 | | |
409 | | /* combine it with the original join condition */ |
410 | 0 | parse->mergeJoinCondition = |
411 | 0 | (Node *) make_and_qual((Node *) ntest, parse->mergeJoinCondition); |
412 | 0 | } |
413 | 0 | else |
414 | 0 | parse->mergeJoinCondition = NULL; /* join condition not needed */ |
415 | 0 | } |
416 | | |
417 | | /* |
418 | | * preprocess_relation_rtes |
419 | | * Do the preprocessing work for any relation RTEs in the FROM clause. |
420 | | * |
421 | | * This scans the rangetable for relation RTEs and retrieves the necessary |
422 | | * catalog information for each relation. Using this information, it clears |
423 | | * the inh flag for any relation that has no children, collects not-null |
424 | | * attribute numbers for any relation that has column not-null constraints, and |
425 | | * expands virtual generated columns for any relation that contains them. |
426 | | * |
427 | | * Note that expanding virtual generated columns may cause the query tree to |
428 | | * have new copies of rangetable entries. Therefore, we have to use list_nth |
429 | | * instead of foreach when iterating over the query's rangetable. |
430 | | * |
431 | | * Returns a modified copy of the query tree, if any relations with virtual |
432 | | * generated columns are present. |
433 | | */ |
434 | | Query * |
435 | | preprocess_relation_rtes(PlannerInfo *root) |
436 | 0 | { |
437 | 0 | Query *parse = root->parse; |
438 | 0 | int rtable_size; |
439 | 0 | int rt_index; |
440 | |
|
441 | 0 | rtable_size = list_length(parse->rtable); |
442 | |
|
443 | 0 | for (rt_index = 0; rt_index < rtable_size; rt_index++) |
444 | 0 | { |
445 | 0 | RangeTblEntry *rte = rt_fetch(rt_index + 1, parse->rtable); |
446 | 0 | Relation relation; |
447 | | |
448 | | /* We only care about relation RTEs. */ |
449 | 0 | if (rte->rtekind != RTE_RELATION) |
450 | 0 | continue; |
451 | | |
452 | | /* |
453 | | * We need not lock the relation since it was already locked by the |
454 | | * rewriter. |
455 | | */ |
456 | 0 | relation = table_open(rte->relid, NoLock); |
457 | | |
458 | | /* |
459 | | * Check to see if the relation actually has any children; if not, |
460 | | * clear the inh flag so we can treat it as a plain base relation. |
461 | | * |
462 | | * Note: this could give a false-positive result, if the rel once had |
463 | | * children but no longer does. We used to be able to clear rte->inh |
464 | | * later on when we discovered that, but no more; we have to handle |
465 | | * such cases as full-fledged inheritance. |
466 | | */ |
467 | 0 | if (rte->inh) |
468 | 0 | rte->inh = relation->rd_rel->relhassubclass; |
469 | | |
470 | | /* |
471 | | * Check to see if the relation has any column not-null constraints; |
472 | | * if so, retrieve the constraint information and store it in a |
473 | | * relation OID based hash table. |
474 | | */ |
475 | 0 | get_relation_notnullatts(root, relation); |
476 | | |
477 | | /* |
478 | | * Check to see if the relation has any virtual generated columns; if |
479 | | * so, replace all Var nodes in the query that reference these columns |
480 | | * with the generation expressions. |
481 | | */ |
482 | 0 | parse = expand_virtual_generated_columns(root, parse, |
483 | 0 | rte, rt_index + 1, |
484 | 0 | relation); |
485 | |
|
486 | 0 | table_close(relation, NoLock); |
487 | 0 | } |
488 | |
|
489 | 0 | return parse; |
490 | 0 | } |
491 | | |
492 | | /* |
493 | | * expand_virtual_generated_columns |
494 | | * Expand virtual generated columns for the given relation. |
495 | | * |
496 | | * This checks whether the given relation has any virtual generated columns, |
497 | | * and if so, replaces all Var nodes in the query that reference those columns |
498 | | * with their generation expressions. |
499 | | * |
500 | | * Returns a modified copy of the query tree if the relation contains virtual |
501 | | * generated columns. |
502 | | */ |
503 | | static Query * |
504 | | expand_virtual_generated_columns(PlannerInfo *root, Query *parse, |
505 | | RangeTblEntry *rte, int rt_index, |
506 | | Relation relation) |
507 | 0 | { |
508 | 0 | TupleDesc tupdesc; |
509 | | |
510 | | /* Only normal relations can have virtual generated columns */ |
511 | 0 | Assert(rte->rtekind == RTE_RELATION); |
512 | |
|
513 | 0 | tupdesc = RelationGetDescr(relation); |
514 | 0 | if (tupdesc->constr && tupdesc->constr->has_generated_virtual) |
515 | 0 | { |
516 | 0 | List *tlist = NIL; |
517 | 0 | pullup_replace_vars_context rvcontext; |
518 | 0 | List *save_exclRelTlist = NIL; |
519 | |
|
520 | 0 | for (int i = 0; i < tupdesc->natts; i++) |
521 | 0 | { |
522 | 0 | Form_pg_attribute attr = TupleDescAttr(tupdesc, i); |
523 | 0 | TargetEntry *tle; |
524 | |
|
525 | 0 | if (attr->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL) |
526 | 0 | { |
527 | 0 | Node *defexpr; |
528 | |
|
529 | 0 | defexpr = build_generation_expression(relation, i + 1); |
530 | 0 | ChangeVarNodes(defexpr, 1, rt_index, 0); |
531 | |
|
532 | 0 | tle = makeTargetEntry((Expr *) defexpr, i + 1, 0, false); |
533 | 0 | tlist = lappend(tlist, tle); |
534 | 0 | } |
535 | 0 | else |
536 | 0 | { |
537 | 0 | Var *var; |
538 | |
|
539 | 0 | var = makeVar(rt_index, |
540 | 0 | i + 1, |
541 | 0 | attr->atttypid, |
542 | 0 | attr->atttypmod, |
543 | 0 | attr->attcollation, |
544 | 0 | 0); |
545 | |
|
546 | 0 | tle = makeTargetEntry((Expr *) var, i + 1, 0, false); |
547 | 0 | tlist = lappend(tlist, tle); |
548 | 0 | } |
549 | 0 | } |
550 | |
|
551 | 0 | Assert(list_length(tlist) > 0); |
552 | 0 | Assert(!rte->lateral); |
553 | | |
554 | | /* |
555 | | * The relation's targetlist items are now in the appropriate form to |
556 | | * insert into the query, except that we may need to wrap them in |
557 | | * PlaceHolderVars. Set up required context data for |
558 | | * pullup_replace_vars. |
559 | | */ |
560 | 0 | rvcontext.root = root; |
561 | 0 | rvcontext.targetlist = tlist; |
562 | 0 | rvcontext.target_rte = rte; |
563 | 0 | rvcontext.result_relation = parse->resultRelation; |
564 | | /* won't need these values */ |
565 | 0 | rvcontext.relids = NULL; |
566 | 0 | rvcontext.nullinfo = NULL; |
567 | | /* pass NULL for outer_hasSubLinks */ |
568 | 0 | rvcontext.outer_hasSubLinks = NULL; |
569 | 0 | rvcontext.varno = rt_index; |
570 | | /* this flag will be set below, if needed */ |
571 | 0 | rvcontext.wrap_option = REPLACE_WRAP_NONE; |
572 | | /* initialize cache array with indexes 0 .. length(tlist) */ |
573 | 0 | rvcontext.rv_cache = palloc0_array(Node *, list_length(tlist) + 1); |
574 | | |
575 | | /* |
576 | | * If the query uses grouping sets, we need a PlaceHolderVar for each |
577 | | * expression of the relation's targetlist items. (See comments in |
578 | | * pull_up_simple_subquery().) |
579 | | */ |
580 | 0 | if (parse->groupingSets) |
581 | 0 | rvcontext.wrap_option = REPLACE_WRAP_ALL; |
582 | | |
583 | | /* |
584 | | * Apply pullup variable replacement throughout the query tree. |
585 | | * |
586 | | * We intentionally do not touch the EXCLUDED pseudo-relation's |
587 | | * targetlist here. Various places in the planner assume that it |
588 | | * contains only Vars, and we want that to remain the case. More |
589 | | * importantly, we don't want setrefs.c to turn any expanded |
590 | | * EXCLUDED.virtual_column expressions in other parts of the query |
591 | | * back into Vars referencing the original virtual column, which |
592 | | * set_plan_refs() would do if exclRelTlist contained matching |
593 | | * expressions. |
594 | | */ |
595 | 0 | if (parse->onConflict) |
596 | 0 | { |
597 | 0 | save_exclRelTlist = parse->onConflict->exclRelTlist; |
598 | 0 | parse->onConflict->exclRelTlist = NIL; |
599 | 0 | } |
600 | |
|
601 | 0 | parse = (Query *) pullup_replace_vars((Node *) parse, &rvcontext); |
602 | |
|
603 | 0 | if (parse->onConflict) |
604 | 0 | parse->onConflict->exclRelTlist = save_exclRelTlist; |
605 | 0 | } |
606 | |
|
607 | 0 | return parse; |
608 | 0 | } |
609 | | |
610 | | /* |
611 | | * replace_empty_jointree |
612 | | * If the Query's jointree is empty, replace it with a dummy RTE_RESULT |
613 | | * relation. |
614 | | * |
615 | | * By doing this, we can avoid a bunch of corner cases that formerly existed |
616 | | * for SELECTs with omitted FROM clauses. An example is that a subquery |
617 | | * with empty jointree previously could not be pulled up, because that would |
618 | | * have resulted in an empty relid set, making the subquery not uniquely |
619 | | * identifiable for join or PlaceHolderVar processing. |
620 | | * |
621 | | * Unlike most other functions in this file, this function doesn't recurse; |
622 | | * we rely on other processing to invoke it on sub-queries at suitable times. |
623 | | */ |
624 | | void |
625 | | replace_empty_jointree(Query *parse) |
626 | 0 | { |
627 | 0 | RangeTblEntry *rte; |
628 | 0 | Index rti; |
629 | 0 | RangeTblRef *rtr; |
630 | | |
631 | | /* Nothing to do if jointree is already nonempty */ |
632 | 0 | if (parse->jointree->fromlist != NIL) |
633 | 0 | return; |
634 | | |
635 | | /* We mustn't change it in the top level of a setop tree, either */ |
636 | 0 | if (parse->setOperations) |
637 | 0 | return; |
638 | | |
639 | | /* Create suitable RTE */ |
640 | 0 | rte = makeNode(RangeTblEntry); |
641 | 0 | rte->rtekind = RTE_RESULT; |
642 | 0 | rte->eref = makeAlias("*RESULT*", NIL); |
643 | | |
644 | | /* Add it to rangetable */ |
645 | 0 | parse->rtable = lappend(parse->rtable, rte); |
646 | 0 | rti = list_length(parse->rtable); |
647 | | |
648 | | /* And jam a reference into the jointree */ |
649 | 0 | rtr = makeNode(RangeTblRef); |
650 | 0 | rtr->rtindex = rti; |
651 | 0 | parse->jointree->fromlist = list_make1(rtr); |
652 | 0 | } |
653 | | |
654 | | /* |
655 | | * pull_up_sublinks |
656 | | * Attempt to pull up ANY and EXISTS SubLinks to be treated as |
657 | | * semijoins or anti-semijoins. |
658 | | * |
659 | | * A clause "foo op ANY (sub-SELECT)" can be processed by pulling the |
660 | | * sub-SELECT up to become a rangetable entry and treating the implied |
661 | | * comparisons as quals of a semijoin. However, this optimization *only* |
662 | | * works at the top level of WHERE or a JOIN/ON clause, because we cannot |
663 | | * distinguish whether the ANY ought to return FALSE or NULL in cases |
664 | | * involving NULL inputs. Also, in an outer join's ON clause we can only |
665 | | * do this if the sublink is degenerate (ie, references only the nullable |
666 | | * side of the join). In that case it is legal to push the semijoin |
667 | | * down into the nullable side of the join. If the sublink references any |
668 | | * nonnullable-side variables then it would have to be evaluated as part |
669 | | * of the outer join, which makes things way too complicated. |
670 | | * |
671 | | * Under similar conditions, EXISTS and NOT EXISTS clauses can be handled |
672 | | * by pulling up the sub-SELECT and creating a semijoin or anti-semijoin. |
673 | | * |
674 | | * This routine searches for such clauses and does the necessary parsetree |
675 | | * transformations if any are found. |
676 | | * |
677 | | * This routine has to run before preprocess_expression(), so the quals |
678 | | * clauses are not yet reduced to implicit-AND format, and are not guaranteed |
679 | | * to be AND/OR-flat either. That means we need to recursively search through |
680 | | * explicit AND clauses. We stop as soon as we hit a non-AND item. |
681 | | */ |
682 | | void |
683 | | pull_up_sublinks(PlannerInfo *root) |
684 | 0 | { |
685 | 0 | Node *jtnode; |
686 | 0 | Relids relids; |
687 | | |
688 | | /* Begin recursion through the jointree */ |
689 | 0 | jtnode = pull_up_sublinks_jointree_recurse(root, |
690 | 0 | (Node *) root->parse->jointree, |
691 | 0 | &relids); |
692 | | |
693 | | /* |
694 | | * root->parse->jointree must always be a FromExpr, so insert a dummy one |
695 | | * if we got a bare RangeTblRef or JoinExpr out of the recursion. |
696 | | */ |
697 | 0 | if (IsA(jtnode, FromExpr)) |
698 | 0 | root->parse->jointree = (FromExpr *) jtnode; |
699 | 0 | else |
700 | 0 | root->parse->jointree = makeFromExpr(list_make1(jtnode), NULL); |
701 | 0 | } |
702 | | |
703 | | /* |
704 | | * Recurse through jointree nodes for pull_up_sublinks() |
705 | | * |
706 | | * In addition to returning the possibly-modified jointree node, we return |
707 | | * a relids set of the contained rels into *relids. |
708 | | */ |
709 | | static Node * |
710 | | pull_up_sublinks_jointree_recurse(PlannerInfo *root, Node *jtnode, |
711 | | Relids *relids) |
712 | 0 | { |
713 | | /* Since this function recurses, it could be driven to stack overflow. */ |
714 | 0 | check_stack_depth(); |
715 | |
|
716 | 0 | if (jtnode == NULL) |
717 | 0 | { |
718 | 0 | *relids = NULL; |
719 | 0 | } |
720 | 0 | else if (IsA(jtnode, RangeTblRef)) |
721 | 0 | { |
722 | 0 | int varno = ((RangeTblRef *) jtnode)->rtindex; |
723 | |
|
724 | 0 | *relids = bms_make_singleton(varno); |
725 | | /* jtnode is returned unmodified */ |
726 | 0 | } |
727 | 0 | else if (IsA(jtnode, FromExpr)) |
728 | 0 | { |
729 | 0 | FromExpr *f = (FromExpr *) jtnode; |
730 | 0 | List *newfromlist = NIL; |
731 | 0 | Relids frelids = NULL; |
732 | 0 | FromExpr *newf; |
733 | 0 | Node *jtlink; |
734 | 0 | ListCell *l; |
735 | | |
736 | | /* First, recurse to process children and collect their relids */ |
737 | 0 | foreach(l, f->fromlist) |
738 | 0 | { |
739 | 0 | Node *newchild; |
740 | 0 | Relids childrelids; |
741 | |
|
742 | 0 | newchild = pull_up_sublinks_jointree_recurse(root, |
743 | 0 | lfirst(l), |
744 | 0 | &childrelids); |
745 | 0 | newfromlist = lappend(newfromlist, newchild); |
746 | 0 | frelids = bms_join(frelids, childrelids); |
747 | 0 | } |
748 | | /* Build the replacement FromExpr; no quals yet */ |
749 | 0 | newf = makeFromExpr(newfromlist, NULL); |
750 | | /* Set up a link representing the rebuilt jointree */ |
751 | 0 | jtlink = (Node *) newf; |
752 | | /* Now process qual --- all children are available for use */ |
753 | 0 | newf->quals = pull_up_sublinks_qual_recurse(root, f->quals, |
754 | 0 | &jtlink, frelids, |
755 | 0 | NULL, NULL); |
756 | | |
757 | | /* |
758 | | * Note that the result will be either newf, or a stack of JoinExprs |
759 | | * with newf at the base. We rely on subsequent optimization steps to |
760 | | * flatten this and rearrange the joins as needed. |
761 | | * |
762 | | * Although we could include the pulled-up subqueries in the returned |
763 | | * relids, there's no need since upper quals couldn't refer to their |
764 | | * outputs anyway. |
765 | | */ |
766 | 0 | *relids = frelids; |
767 | 0 | jtnode = jtlink; |
768 | 0 | } |
769 | 0 | else if (IsA(jtnode, JoinExpr)) |
770 | 0 | { |
771 | 0 | JoinExpr *j; |
772 | 0 | Relids leftrelids; |
773 | 0 | Relids rightrelids; |
774 | 0 | Node *jtlink; |
775 | | |
776 | | /* |
777 | | * Make a modifiable copy of join node, but don't bother copying its |
778 | | * subnodes (yet). |
779 | | */ |
780 | 0 | j = palloc_object(JoinExpr); |
781 | 0 | memcpy(j, jtnode, sizeof(JoinExpr)); |
782 | 0 | jtlink = (Node *) j; |
783 | | |
784 | | /* Recurse to process children and collect their relids */ |
785 | 0 | j->larg = pull_up_sublinks_jointree_recurse(root, j->larg, |
786 | 0 | &leftrelids); |
787 | 0 | j->rarg = pull_up_sublinks_jointree_recurse(root, j->rarg, |
788 | 0 | &rightrelids); |
789 | | |
790 | | /* |
791 | | * Now process qual, showing appropriate child relids as available, |
792 | | * and attach any pulled-up jointree items at the right place. In the |
793 | | * inner-join case we put new JoinExprs above the existing one (much |
794 | | * as for a FromExpr-style join). In outer-join cases the new |
795 | | * JoinExprs must go into the nullable side of the outer join. The |
796 | | * point of the available_rels machinations is to ensure that we only |
797 | | * pull up quals for which that's okay. |
798 | | * |
799 | | * We don't expect to see any pre-existing JOIN_SEMI, JOIN_ANTI, |
800 | | * JOIN_RIGHT_SEMI, or JOIN_RIGHT_ANTI jointypes here. |
801 | | */ |
802 | 0 | switch (j->jointype) |
803 | 0 | { |
804 | 0 | case JOIN_INNER: |
805 | 0 | j->quals = pull_up_sublinks_qual_recurse(root, j->quals, |
806 | 0 | &jtlink, |
807 | 0 | bms_union(leftrelids, |
808 | 0 | rightrelids), |
809 | 0 | NULL, NULL); |
810 | 0 | break; |
811 | 0 | case JOIN_LEFT: |
812 | 0 | j->quals = pull_up_sublinks_qual_recurse(root, j->quals, |
813 | 0 | &j->rarg, |
814 | 0 | rightrelids, |
815 | 0 | NULL, NULL); |
816 | 0 | break; |
817 | 0 | case JOIN_FULL: |
818 | | /* can't do anything with full-join quals */ |
819 | 0 | break; |
820 | 0 | case JOIN_RIGHT: |
821 | 0 | j->quals = pull_up_sublinks_qual_recurse(root, j->quals, |
822 | 0 | &j->larg, |
823 | 0 | leftrelids, |
824 | 0 | NULL, NULL); |
825 | 0 | break; |
826 | 0 | default: |
827 | 0 | elog(ERROR, "unrecognized join type: %d", |
828 | 0 | (int) j->jointype); |
829 | 0 | break; |
830 | 0 | } |
831 | | |
832 | | /* |
833 | | * Although we could include the pulled-up subqueries in the returned |
834 | | * relids, there's no need since upper quals couldn't refer to their |
835 | | * outputs anyway. But we *do* need to include the join's own rtindex |
836 | | * because we haven't yet collapsed join alias variables, so upper |
837 | | * levels would mistakenly think they couldn't use references to this |
838 | | * join. |
839 | | */ |
840 | 0 | *relids = bms_join(leftrelids, rightrelids); |
841 | 0 | if (j->rtindex) |
842 | 0 | *relids = bms_add_member(*relids, j->rtindex); |
843 | 0 | jtnode = jtlink; |
844 | 0 | } |
845 | 0 | else |
846 | 0 | elog(ERROR, "unrecognized node type: %d", |
847 | 0 | (int) nodeTag(jtnode)); |
848 | 0 | return jtnode; |
849 | 0 | } |
850 | | |
851 | | /* |
852 | | * Recurse through top-level qual nodes for pull_up_sublinks() |
853 | | * |
854 | | * jtlink1 points to the link in the jointree where any new JoinExprs should |
855 | | * be inserted if they reference available_rels1 (i.e., available_rels1 |
856 | | * denotes the relations present underneath jtlink1). Optionally, jtlink2 can |
857 | | * point to a second link where new JoinExprs should be inserted if they |
858 | | * reference available_rels2 (pass NULL for both those arguments if not used). |
859 | | * Note that SubLinks referencing both sets of variables cannot be optimized. |
860 | | * If we find multiple pull-up-able SubLinks, they'll get stacked onto jtlink1 |
861 | | * and/or jtlink2 in the order we encounter them. We rely on subsequent |
862 | | * optimization to rearrange the stack if appropriate. |
863 | | * |
864 | | * Returns the replacement qual node, or NULL if the qual should be removed. |
865 | | */ |
866 | | static Node * |
867 | | pull_up_sublinks_qual_recurse(PlannerInfo *root, Node *node, |
868 | | Node **jtlink1, Relids available_rels1, |
869 | | Node **jtlink2, Relids available_rels2) |
870 | 0 | { |
871 | 0 | if (node == NULL) |
872 | 0 | return NULL; |
873 | 0 | if (IsA(node, SubLink)) |
874 | 0 | { |
875 | 0 | SubLink *sublink = (SubLink *) node; |
876 | 0 | JoinExpr *j; |
877 | 0 | Relids child_rels; |
878 | | |
879 | | /* Is it a convertible ANY or EXISTS clause? */ |
880 | 0 | if (sublink->subLinkType == ANY_SUBLINK) |
881 | 0 | { |
882 | 0 | ScalarArrayOpExpr *saop; |
883 | |
|
884 | 0 | if ((saop = convert_VALUES_to_ANY(root, |
885 | 0 | sublink->testexpr, |
886 | 0 | (Query *) sublink->subselect)) != NULL) |
887 | 0 | { |
888 | | /* |
889 | | * The VALUES sequence was simplified. Nothing more to do |
890 | | * here. |
891 | | */ |
892 | 0 | return (Node *) saop; |
893 | 0 | } |
894 | | |
895 | 0 | if ((j = convert_ANY_sublink_to_join(root, sublink, false, |
896 | 0 | available_rels1)) != NULL) |
897 | 0 | { |
898 | | /* Yes; insert the new join node into the join tree */ |
899 | 0 | j->larg = *jtlink1; |
900 | 0 | *jtlink1 = (Node *) j; |
901 | | /* Recursively process pulled-up jointree nodes */ |
902 | 0 | j->rarg = pull_up_sublinks_jointree_recurse(root, |
903 | 0 | j->rarg, |
904 | 0 | &child_rels); |
905 | | |
906 | | /* |
907 | | * Now recursively process the pulled-up quals. Any inserted |
908 | | * joins can get stacked onto either j->larg or j->rarg, |
909 | | * depending on which rels they reference. |
910 | | */ |
911 | 0 | j->quals = pull_up_sublinks_qual_recurse(root, |
912 | 0 | j->quals, |
913 | 0 | &j->larg, |
914 | 0 | available_rels1, |
915 | 0 | &j->rarg, |
916 | 0 | child_rels); |
917 | | /* Return NULL representing constant TRUE */ |
918 | 0 | return NULL; |
919 | 0 | } |
920 | 0 | if (available_rels2 != NULL && |
921 | 0 | (j = convert_ANY_sublink_to_join(root, sublink, false, |
922 | 0 | available_rels2)) != NULL) |
923 | 0 | { |
924 | | /* Yes; insert the new join node into the join tree */ |
925 | 0 | j->larg = *jtlink2; |
926 | 0 | *jtlink2 = (Node *) j; |
927 | | /* Recursively process pulled-up jointree nodes */ |
928 | 0 | j->rarg = pull_up_sublinks_jointree_recurse(root, |
929 | 0 | j->rarg, |
930 | 0 | &child_rels); |
931 | | |
932 | | /* |
933 | | * Now recursively process the pulled-up quals. Any inserted |
934 | | * joins can get stacked onto either j->larg or j->rarg, |
935 | | * depending on which rels they reference. |
936 | | */ |
937 | 0 | j->quals = pull_up_sublinks_qual_recurse(root, |
938 | 0 | j->quals, |
939 | 0 | &j->larg, |
940 | 0 | available_rels2, |
941 | 0 | &j->rarg, |
942 | 0 | child_rels); |
943 | | /* Return NULL representing constant TRUE */ |
944 | 0 | return NULL; |
945 | 0 | } |
946 | 0 | } |
947 | 0 | else if (sublink->subLinkType == EXISTS_SUBLINK) |
948 | 0 | { |
949 | 0 | if ((j = convert_EXISTS_sublink_to_join(root, sublink, false, |
950 | 0 | available_rels1)) != NULL) |
951 | 0 | { |
952 | | /* Yes; insert the new join node into the join tree */ |
953 | 0 | j->larg = *jtlink1; |
954 | 0 | *jtlink1 = (Node *) j; |
955 | | /* Recursively process pulled-up jointree nodes */ |
956 | 0 | j->rarg = pull_up_sublinks_jointree_recurse(root, |
957 | 0 | j->rarg, |
958 | 0 | &child_rels); |
959 | | |
960 | | /* |
961 | | * Now recursively process the pulled-up quals. Any inserted |
962 | | * joins can get stacked onto either j->larg or j->rarg, |
963 | | * depending on which rels they reference. |
964 | | */ |
965 | 0 | j->quals = pull_up_sublinks_qual_recurse(root, |
966 | 0 | j->quals, |
967 | 0 | &j->larg, |
968 | 0 | available_rels1, |
969 | 0 | &j->rarg, |
970 | 0 | child_rels); |
971 | | /* Return NULL representing constant TRUE */ |
972 | 0 | return NULL; |
973 | 0 | } |
974 | 0 | if (available_rels2 != NULL && |
975 | 0 | (j = convert_EXISTS_sublink_to_join(root, sublink, false, |
976 | 0 | available_rels2)) != NULL) |
977 | 0 | { |
978 | | /* Yes; insert the new join node into the join tree */ |
979 | 0 | j->larg = *jtlink2; |
980 | 0 | *jtlink2 = (Node *) j; |
981 | | /* Recursively process pulled-up jointree nodes */ |
982 | 0 | j->rarg = pull_up_sublinks_jointree_recurse(root, |
983 | 0 | j->rarg, |
984 | 0 | &child_rels); |
985 | | |
986 | | /* |
987 | | * Now recursively process the pulled-up quals. Any inserted |
988 | | * joins can get stacked onto either j->larg or j->rarg, |
989 | | * depending on which rels they reference. |
990 | | */ |
991 | 0 | j->quals = pull_up_sublinks_qual_recurse(root, |
992 | 0 | j->quals, |
993 | 0 | &j->larg, |
994 | 0 | available_rels2, |
995 | 0 | &j->rarg, |
996 | 0 | child_rels); |
997 | | /* Return NULL representing constant TRUE */ |
998 | 0 | return NULL; |
999 | 0 | } |
1000 | 0 | } |
1001 | | /* Else return it unmodified */ |
1002 | 0 | return node; |
1003 | 0 | } |
1004 | 0 | if (is_notclause(node)) |
1005 | 0 | { |
1006 | | /* If the immediate argument of NOT is ANY or EXISTS, try to convert */ |
1007 | 0 | SubLink *sublink = (SubLink *) get_notclausearg((Expr *) node); |
1008 | 0 | JoinExpr *j; |
1009 | 0 | Relids child_rels; |
1010 | |
|
1011 | 0 | if (sublink && IsA(sublink, SubLink)) |
1012 | 0 | { |
1013 | 0 | if (sublink->subLinkType == ANY_SUBLINK) |
1014 | 0 | { |
1015 | 0 | if ((j = convert_ANY_sublink_to_join(root, sublink, true, |
1016 | 0 | available_rels1)) != NULL) |
1017 | 0 | { |
1018 | | /* Yes; insert the new join node into the join tree */ |
1019 | 0 | j->larg = *jtlink1; |
1020 | 0 | *jtlink1 = (Node *) j; |
1021 | | /* Recursively process pulled-up jointree nodes */ |
1022 | 0 | j->rarg = pull_up_sublinks_jointree_recurse(root, |
1023 | 0 | j->rarg, |
1024 | 0 | &child_rels); |
1025 | | |
1026 | | /* |
1027 | | * Now recursively process the pulled-up quals. Because |
1028 | | * we are underneath a NOT, we can't pull up sublinks that |
1029 | | * reference the left-hand stuff, but it's still okay to |
1030 | | * pull up sublinks referencing j->rarg. |
1031 | | */ |
1032 | 0 | j->quals = pull_up_sublinks_qual_recurse(root, |
1033 | 0 | j->quals, |
1034 | 0 | &j->rarg, |
1035 | 0 | child_rels, |
1036 | 0 | NULL, NULL); |
1037 | | /* Return NULL representing constant TRUE */ |
1038 | 0 | return NULL; |
1039 | 0 | } |
1040 | 0 | if (available_rels2 != NULL && |
1041 | 0 | (j = convert_ANY_sublink_to_join(root, sublink, true, |
1042 | 0 | available_rels2)) != NULL) |
1043 | 0 | { |
1044 | | /* Yes; insert the new join node into the join tree */ |
1045 | 0 | j->larg = *jtlink2; |
1046 | 0 | *jtlink2 = (Node *) j; |
1047 | | /* Recursively process pulled-up jointree nodes */ |
1048 | 0 | j->rarg = pull_up_sublinks_jointree_recurse(root, |
1049 | 0 | j->rarg, |
1050 | 0 | &child_rels); |
1051 | | |
1052 | | /* |
1053 | | * Now recursively process the pulled-up quals. Because |
1054 | | * we are underneath a NOT, we can't pull up sublinks that |
1055 | | * reference the left-hand stuff, but it's still okay to |
1056 | | * pull up sublinks referencing j->rarg. |
1057 | | */ |
1058 | 0 | j->quals = pull_up_sublinks_qual_recurse(root, |
1059 | 0 | j->quals, |
1060 | 0 | &j->rarg, |
1061 | 0 | child_rels, |
1062 | 0 | NULL, NULL); |
1063 | | /* Return NULL representing constant TRUE */ |
1064 | 0 | return NULL; |
1065 | 0 | } |
1066 | 0 | } |
1067 | 0 | else if (sublink->subLinkType == EXISTS_SUBLINK) |
1068 | 0 | { |
1069 | 0 | if ((j = convert_EXISTS_sublink_to_join(root, sublink, true, |
1070 | 0 | available_rels1)) != NULL) |
1071 | 0 | { |
1072 | | /* Yes; insert the new join node into the join tree */ |
1073 | 0 | j->larg = *jtlink1; |
1074 | 0 | *jtlink1 = (Node *) j; |
1075 | | /* Recursively process pulled-up jointree nodes */ |
1076 | 0 | j->rarg = pull_up_sublinks_jointree_recurse(root, |
1077 | 0 | j->rarg, |
1078 | 0 | &child_rels); |
1079 | | |
1080 | | /* |
1081 | | * Now recursively process the pulled-up quals. Because |
1082 | | * we are underneath a NOT, we can't pull up sublinks that |
1083 | | * reference the left-hand stuff, but it's still okay to |
1084 | | * pull up sublinks referencing j->rarg. |
1085 | | */ |
1086 | 0 | j->quals = pull_up_sublinks_qual_recurse(root, |
1087 | 0 | j->quals, |
1088 | 0 | &j->rarg, |
1089 | 0 | child_rels, |
1090 | 0 | NULL, NULL); |
1091 | | /* Return NULL representing constant TRUE */ |
1092 | 0 | return NULL; |
1093 | 0 | } |
1094 | 0 | if (available_rels2 != NULL && |
1095 | 0 | (j = convert_EXISTS_sublink_to_join(root, sublink, true, |
1096 | 0 | available_rels2)) != NULL) |
1097 | 0 | { |
1098 | | /* Yes; insert the new join node into the join tree */ |
1099 | 0 | j->larg = *jtlink2; |
1100 | 0 | *jtlink2 = (Node *) j; |
1101 | | /* Recursively process pulled-up jointree nodes */ |
1102 | 0 | j->rarg = pull_up_sublinks_jointree_recurse(root, |
1103 | 0 | j->rarg, |
1104 | 0 | &child_rels); |
1105 | | |
1106 | | /* |
1107 | | * Now recursively process the pulled-up quals. Because |
1108 | | * we are underneath a NOT, we can't pull up sublinks that |
1109 | | * reference the left-hand stuff, but it's still okay to |
1110 | | * pull up sublinks referencing j->rarg. |
1111 | | */ |
1112 | 0 | j->quals = pull_up_sublinks_qual_recurse(root, |
1113 | 0 | j->quals, |
1114 | 0 | &j->rarg, |
1115 | 0 | child_rels, |
1116 | 0 | NULL, NULL); |
1117 | | /* Return NULL representing constant TRUE */ |
1118 | 0 | return NULL; |
1119 | 0 | } |
1120 | 0 | } |
1121 | 0 | } |
1122 | | /* Else return it unmodified */ |
1123 | 0 | return node; |
1124 | 0 | } |
1125 | 0 | if (is_andclause(node)) |
1126 | 0 | { |
1127 | | /* Recurse into AND clause */ |
1128 | 0 | List *newclauses = NIL; |
1129 | 0 | ListCell *l; |
1130 | |
|
1131 | 0 | foreach(l, ((BoolExpr *) node)->args) |
1132 | 0 | { |
1133 | 0 | Node *oldclause = (Node *) lfirst(l); |
1134 | 0 | Node *newclause; |
1135 | |
|
1136 | 0 | newclause = pull_up_sublinks_qual_recurse(root, |
1137 | 0 | oldclause, |
1138 | 0 | jtlink1, |
1139 | 0 | available_rels1, |
1140 | 0 | jtlink2, |
1141 | 0 | available_rels2); |
1142 | 0 | if (newclause) |
1143 | 0 | newclauses = lappend(newclauses, newclause); |
1144 | 0 | } |
1145 | | /* We might have got back fewer clauses than we started with */ |
1146 | 0 | if (newclauses == NIL) |
1147 | 0 | return NULL; |
1148 | 0 | else if (list_length(newclauses) == 1) |
1149 | 0 | return (Node *) linitial(newclauses); |
1150 | 0 | else |
1151 | 0 | return (Node *) make_andclause(newclauses); |
1152 | 0 | } |
1153 | | /* Stop if not an AND */ |
1154 | 0 | return node; |
1155 | 0 | } |
1156 | | |
1157 | | /* |
1158 | | * preprocess_function_rtes |
1159 | | * Constant-simplify any FUNCTION RTEs in the FROM clause, and then |
1160 | | * attempt to "inline" any that can be converted to simple subqueries. |
1161 | | * |
1162 | | * If an RTE_FUNCTION rtable entry invokes a set-returning SQL function that |
1163 | | * contains just a simple SELECT, we can convert the rtable entry to an |
1164 | | * RTE_SUBQUERY entry exposing the SELECT directly. Other sorts of functions |
1165 | | * are also inline-able if they have a support function that can generate |
1166 | | * the replacement sub-Query. This is especially useful if the subquery can |
1167 | | * then be "pulled up" for further optimization, but we do it even if not, |
1168 | | * to reduce executor overhead. |
1169 | | * |
1170 | | * This has to be done before we have started to do any optimization of |
1171 | | * subqueries, else any such steps wouldn't get applied to subqueries |
1172 | | * obtained via inlining. However, we do it after pull_up_sublinks |
1173 | | * so that we can inline any functions used in SubLink subselects. |
1174 | | * |
1175 | | * The reason for applying const-simplification at this stage is that |
1176 | | * (a) we'd need to do it anyway to inline a SRF, and (b) by doing it now, |
1177 | | * we can be sure that pull_up_constant_function() will see constants |
1178 | | * if there are constants to be seen. This approach also guarantees |
1179 | | * that every FUNCTION RTE has been const-simplified, allowing planner.c's |
1180 | | * preprocess_expression() to skip doing it again. |
1181 | | * |
1182 | | * Like most of the planner, this feels free to scribble on its input data |
1183 | | * structure. |
1184 | | */ |
1185 | | void |
1186 | | preprocess_function_rtes(PlannerInfo *root) |
1187 | 0 | { |
1188 | 0 | ListCell *rt; |
1189 | |
|
1190 | 0 | foreach(rt, root->parse->rtable) |
1191 | 0 | { |
1192 | 0 | RangeTblEntry *rte = (RangeTblEntry *) lfirst(rt); |
1193 | |
|
1194 | 0 | if (rte->rtekind == RTE_FUNCTION) |
1195 | 0 | { |
1196 | 0 | Query *funcquery; |
1197 | | |
1198 | | /* Apply const-simplification */ |
1199 | 0 | rte->functions = (List *) |
1200 | 0 | eval_const_expressions(root, (Node *) rte->functions); |
1201 | | |
1202 | | /* Check safety of expansion, and expand if possible */ |
1203 | 0 | funcquery = inline_function_in_from(root, rte); |
1204 | 0 | if (funcquery) |
1205 | 0 | { |
1206 | | /* Successful expansion, convert the RTE to a subquery */ |
1207 | 0 | rte->rtekind = RTE_SUBQUERY; |
1208 | 0 | rte->subquery = funcquery; |
1209 | 0 | rte->security_barrier = false; |
1210 | | |
1211 | | /* |
1212 | | * Clear fields that should not be set in a subquery RTE. |
1213 | | * However, we leave rte->functions filled in for the moment, |
1214 | | * in case makeWholeRowVar needs to consult it. We'll clear |
1215 | | * it in setrefs.c (see add_rte_to_flat_rtable) so that this |
1216 | | * abuse of the data structure doesn't escape the planner. |
1217 | | */ |
1218 | 0 | rte->funcordinality = false; |
1219 | 0 | } |
1220 | 0 | } |
1221 | 0 | } |
1222 | 0 | } |
1223 | | |
1224 | | /* |
1225 | | * pull_up_subqueries |
1226 | | * Look for subqueries in the rangetable that can be pulled up into |
1227 | | * the parent query. If the subquery has no special features like |
1228 | | * grouping/aggregation then we can merge it into the parent's jointree. |
1229 | | * Also, subqueries that are simple UNION ALL structures can be |
1230 | | * converted into "append relations". |
1231 | | */ |
1232 | | void |
1233 | | pull_up_subqueries(PlannerInfo *root) |
1234 | 0 | { |
1235 | | /* Top level of jointree must always be a FromExpr */ |
1236 | 0 | Assert(IsA(root->parse->jointree, FromExpr)); |
1237 | | /* Recursion starts with no containing join nor appendrel */ |
1238 | 0 | root->parse->jointree = (FromExpr *) |
1239 | 0 | pull_up_subqueries_recurse(root, (Node *) root->parse->jointree, |
1240 | 0 | NULL, NULL); |
1241 | | /* We should still have a FromExpr */ |
1242 | 0 | Assert(IsA(root->parse->jointree, FromExpr)); |
1243 | 0 | } |
1244 | | |
1245 | | /* |
1246 | | * pull_up_subqueries_recurse |
1247 | | * Recursive guts of pull_up_subqueries. |
1248 | | * |
1249 | | * This recursively processes the jointree and returns a modified jointree. |
1250 | | * |
1251 | | * If this jointree node is within either side of an outer join, then |
1252 | | * lowest_outer_join references the lowest such JoinExpr node; otherwise |
1253 | | * it is NULL. We use this to constrain the effects of LATERAL subqueries. |
1254 | | * |
1255 | | * If we are looking at a member subquery of an append relation, |
1256 | | * containing_appendrel describes that relation; else it is NULL. |
1257 | | * This forces use of the PlaceHolderVar mechanism for all non-Var targetlist |
1258 | | * items, and puts some additional restrictions on what can be pulled up. |
1259 | | * |
1260 | | * A tricky aspect of this code is that if we pull up a subquery we have |
1261 | | * to replace Vars that reference the subquery's outputs throughout the |
1262 | | * parent query, including quals attached to jointree nodes above the one |
1263 | | * we are currently processing! We handle this by being careful to maintain |
1264 | | * validity of the jointree structure while recursing, in the following sense: |
1265 | | * whenever we recurse, all qual expressions in the tree must be reachable |
1266 | | * from the top level, in case the recursive call needs to modify them. |
1267 | | * |
1268 | | * Notice also that we can't turn pullup_replace_vars loose on the whole |
1269 | | * jointree, because it'd return a mutated copy of the tree; we have to |
1270 | | * invoke it just on the quals, instead. This behavior is what makes it |
1271 | | * reasonable to pass lowest_outer_join as a pointer rather than some |
1272 | | * more-indirect way of identifying the lowest OJ. Likewise, we don't |
1273 | | * replace append_rel_list members but only their substructure, so the |
1274 | | * containing_appendrel reference is safe to use. |
1275 | | */ |
1276 | | static Node * |
1277 | | pull_up_subqueries_recurse(PlannerInfo *root, Node *jtnode, |
1278 | | JoinExpr *lowest_outer_join, |
1279 | | AppendRelInfo *containing_appendrel) |
1280 | 0 | { |
1281 | | /* Since this function recurses, it could be driven to stack overflow. */ |
1282 | 0 | check_stack_depth(); |
1283 | | /* Also, since it's a bit expensive, let's check for query cancel. */ |
1284 | 0 | CHECK_FOR_INTERRUPTS(); |
1285 | |
|
1286 | 0 | Assert(jtnode != NULL); |
1287 | 0 | if (IsA(jtnode, RangeTblRef)) |
1288 | 0 | { |
1289 | 0 | int varno = ((RangeTblRef *) jtnode)->rtindex; |
1290 | 0 | RangeTblEntry *rte = rt_fetch(varno, root->parse->rtable); |
1291 | | |
1292 | | /* |
1293 | | * Is this a subquery RTE, and if so, is the subquery simple enough to |
1294 | | * pull up? |
1295 | | * |
1296 | | * If we are looking at an append-relation member, we can't pull it up |
1297 | | * unless is_safe_append_member says so. |
1298 | | */ |
1299 | 0 | if (rte->rtekind == RTE_SUBQUERY && |
1300 | 0 | is_simple_subquery(root, rte->subquery, rte, lowest_outer_join) && |
1301 | 0 | (containing_appendrel == NULL || |
1302 | 0 | is_safe_append_member(rte->subquery))) |
1303 | 0 | return pull_up_simple_subquery(root, jtnode, rte, |
1304 | 0 | lowest_outer_join, |
1305 | 0 | containing_appendrel); |
1306 | | |
1307 | | /* |
1308 | | * Alternatively, is it a simple UNION ALL subquery? If so, flatten |
1309 | | * into an "append relation". |
1310 | | * |
1311 | | * It's safe to do this regardless of whether this query is itself an |
1312 | | * appendrel member. (If you're thinking we should try to flatten the |
1313 | | * two levels of appendrel together, you're right; but we handle that |
1314 | | * in set_append_rel_pathlist, not here.) |
1315 | | */ |
1316 | 0 | if (rte->rtekind == RTE_SUBQUERY && |
1317 | 0 | is_simple_union_all(rte->subquery)) |
1318 | 0 | return pull_up_simple_union_all(root, jtnode, rte); |
1319 | | |
1320 | | /* |
1321 | | * Or perhaps it's a simple VALUES RTE? |
1322 | | * |
1323 | | * We don't allow VALUES pullup below an outer join nor into an |
1324 | | * appendrel (such cases are impossible anyway at the moment). |
1325 | | */ |
1326 | 0 | if (rte->rtekind == RTE_VALUES && |
1327 | 0 | lowest_outer_join == NULL && |
1328 | 0 | containing_appendrel == NULL && |
1329 | 0 | is_simple_values(root, rte)) |
1330 | 0 | return pull_up_simple_values(root, jtnode, rte); |
1331 | | |
1332 | | /* |
1333 | | * Or perhaps it's a FUNCTION RTE that we could inline? |
1334 | | */ |
1335 | 0 | if (rte->rtekind == RTE_FUNCTION) |
1336 | 0 | return pull_up_constant_function(root, jtnode, rte, |
1337 | 0 | containing_appendrel); |
1338 | | |
1339 | | /* Otherwise, do nothing at this node. */ |
1340 | 0 | } |
1341 | 0 | else if (IsA(jtnode, FromExpr)) |
1342 | 0 | { |
1343 | 0 | FromExpr *f = (FromExpr *) jtnode; |
1344 | 0 | ListCell *l; |
1345 | |
|
1346 | 0 | Assert(containing_appendrel == NULL); |
1347 | | /* Recursively transform all the child nodes */ |
1348 | 0 | foreach(l, f->fromlist) |
1349 | 0 | { |
1350 | 0 | lfirst(l) = pull_up_subqueries_recurse(root, lfirst(l), |
1351 | 0 | lowest_outer_join, |
1352 | 0 | NULL); |
1353 | 0 | } |
1354 | 0 | } |
1355 | 0 | else if (IsA(jtnode, JoinExpr)) |
1356 | 0 | { |
1357 | 0 | JoinExpr *j = (JoinExpr *) jtnode; |
1358 | |
|
1359 | 0 | Assert(containing_appendrel == NULL); |
1360 | | /* Recurse, being careful to tell myself when inside outer join */ |
1361 | 0 | switch (j->jointype) |
1362 | 0 | { |
1363 | 0 | case JOIN_INNER: |
1364 | 0 | j->larg = pull_up_subqueries_recurse(root, j->larg, |
1365 | 0 | lowest_outer_join, |
1366 | 0 | NULL); |
1367 | 0 | j->rarg = pull_up_subqueries_recurse(root, j->rarg, |
1368 | 0 | lowest_outer_join, |
1369 | 0 | NULL); |
1370 | 0 | break; |
1371 | 0 | case JOIN_LEFT: |
1372 | 0 | case JOIN_SEMI: |
1373 | 0 | case JOIN_ANTI: |
1374 | 0 | j->larg = pull_up_subqueries_recurse(root, j->larg, |
1375 | 0 | j, |
1376 | 0 | NULL); |
1377 | 0 | j->rarg = pull_up_subqueries_recurse(root, j->rarg, |
1378 | 0 | j, |
1379 | 0 | NULL); |
1380 | 0 | break; |
1381 | 0 | case JOIN_FULL: |
1382 | 0 | j->larg = pull_up_subqueries_recurse(root, j->larg, |
1383 | 0 | j, |
1384 | 0 | NULL); |
1385 | 0 | j->rarg = pull_up_subqueries_recurse(root, j->rarg, |
1386 | 0 | j, |
1387 | 0 | NULL); |
1388 | 0 | break; |
1389 | 0 | case JOIN_RIGHT: |
1390 | 0 | j->larg = pull_up_subqueries_recurse(root, j->larg, |
1391 | 0 | j, |
1392 | 0 | NULL); |
1393 | 0 | j->rarg = pull_up_subqueries_recurse(root, j->rarg, |
1394 | 0 | j, |
1395 | 0 | NULL); |
1396 | 0 | break; |
1397 | 0 | default: |
1398 | 0 | elog(ERROR, "unrecognized join type: %d", |
1399 | 0 | (int) j->jointype); |
1400 | 0 | break; |
1401 | 0 | } |
1402 | 0 | } |
1403 | 0 | else |
1404 | 0 | elog(ERROR, "unrecognized node type: %d", |
1405 | 0 | (int) nodeTag(jtnode)); |
1406 | 0 | return jtnode; |
1407 | 0 | } |
1408 | | |
1409 | | /* |
1410 | | * pull_up_simple_subquery |
1411 | | * Attempt to pull up a single simple subquery. |
1412 | | * |
1413 | | * jtnode is a RangeTblRef that has been tentatively identified as a simple |
1414 | | * subquery by pull_up_subqueries. We return the replacement jointree node, |
1415 | | * or jtnode itself if we determine that the subquery can't be pulled up |
1416 | | * after all. |
1417 | | * |
1418 | | * rte is the RangeTblEntry referenced by jtnode. Remaining parameters are |
1419 | | * as for pull_up_subqueries_recurse. |
1420 | | */ |
1421 | | static Node * |
1422 | | pull_up_simple_subquery(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte, |
1423 | | JoinExpr *lowest_outer_join, |
1424 | | AppendRelInfo *containing_appendrel) |
1425 | 0 | { |
1426 | 0 | Query *parse = root->parse; |
1427 | 0 | int varno = ((RangeTblRef *) jtnode)->rtindex; |
1428 | 0 | Query *subquery; |
1429 | 0 | PlannerInfo *subroot; |
1430 | 0 | int rtoffset; |
1431 | 0 | pullup_replace_vars_context rvcontext; |
1432 | 0 | ListCell *lc; |
1433 | | |
1434 | | /* |
1435 | | * Make a modifiable copy of the subquery to hack on, so that the RTE will |
1436 | | * be left unchanged in case we decide below that we can't pull it up |
1437 | | * after all. |
1438 | | */ |
1439 | 0 | subquery = copyObject(rte->subquery); |
1440 | | |
1441 | | /* |
1442 | | * Create a PlannerInfo data structure for this subquery. |
1443 | | * |
1444 | | * NOTE: the next few steps should match the first processing in |
1445 | | * subquery_planner(). Can we refactor to avoid code duplication, or |
1446 | | * would that just make things uglier? |
1447 | | */ |
1448 | 0 | subroot = makeNode(PlannerInfo); |
1449 | 0 | subroot->parse = subquery; |
1450 | 0 | subroot->glob = root->glob; |
1451 | 0 | subroot->query_level = root->query_level; |
1452 | 0 | subroot->plan_name = root->plan_name; |
1453 | 0 | subroot->alternative_plan_name = root->alternative_plan_name; |
1454 | 0 | subroot->parent_root = root->parent_root; |
1455 | 0 | subroot->plan_params = NIL; |
1456 | 0 | subroot->outer_params = NULL; |
1457 | 0 | subroot->planner_cxt = CurrentMemoryContext; |
1458 | 0 | subroot->init_plans = NIL; |
1459 | 0 | subroot->cte_plan_ids = NIL; |
1460 | 0 | subroot->multiexpr_params = NIL; |
1461 | 0 | subroot->join_domains = NIL; |
1462 | 0 | subroot->eq_classes = NIL; |
1463 | 0 | subroot->ec_merging_done = false; |
1464 | 0 | subroot->last_rinfo_serial = 0; |
1465 | 0 | subroot->all_result_relids = NULL; |
1466 | 0 | subroot->leaf_result_relids = NULL; |
1467 | 0 | subroot->append_rel_list = NIL; |
1468 | 0 | subroot->row_identity_vars = NIL; |
1469 | 0 | subroot->rowMarks = NIL; |
1470 | 0 | memset(subroot->upper_rels, 0, sizeof(subroot->upper_rels)); |
1471 | 0 | memset(subroot->upper_targets, 0, sizeof(subroot->upper_targets)); |
1472 | 0 | subroot->processed_groupClause = NIL; |
1473 | 0 | subroot->processed_distinctClause = NIL; |
1474 | 0 | subroot->processed_tlist = NIL; |
1475 | 0 | subroot->update_colnos = NIL; |
1476 | 0 | subroot->grouping_map = NULL; |
1477 | 0 | subroot->minmax_aggs = NIL; |
1478 | 0 | subroot->qual_security_level = 0; |
1479 | 0 | subroot->placeholdersFrozen = false; |
1480 | 0 | subroot->hasRecursion = false; |
1481 | 0 | subroot->assumeReplanning = false; |
1482 | 0 | subroot->wt_param_id = -1; |
1483 | 0 | subroot->non_recursive_path = NULL; |
1484 | | /* We don't currently need a top JoinDomain for the subroot */ |
1485 | | |
1486 | | /* No CTEs to worry about */ |
1487 | 0 | Assert(subquery->cteList == NIL); |
1488 | | |
1489 | | /* |
1490 | | * Scan the rangetable for relation RTEs and retrieve the necessary |
1491 | | * catalog information for each relation. Using this information, clear |
1492 | | * the inh flag for any relation that has no children, collect not-null |
1493 | | * attribute numbers for any relation that has column not-null |
1494 | | * constraints, and expand virtual generated columns for any relation that |
1495 | | * contains them. |
1496 | | */ |
1497 | 0 | subquery = subroot->parse = preprocess_relation_rtes(subroot); |
1498 | | |
1499 | | /* |
1500 | | * If the FROM clause is empty, replace it with a dummy RTE_RESULT RTE, so |
1501 | | * that we don't need so many special cases to deal with that situation. |
1502 | | */ |
1503 | 0 | replace_empty_jointree(subquery); |
1504 | | |
1505 | | /* |
1506 | | * Pull up any SubLinks within the subquery's quals, so that we don't |
1507 | | * leave unoptimized SubLinks behind. |
1508 | | */ |
1509 | 0 | if (subquery->hasSubLinks) |
1510 | 0 | pull_up_sublinks(subroot); |
1511 | | |
1512 | | /* |
1513 | | * Similarly, preprocess its function RTEs to inline any set-returning |
1514 | | * functions in its rangetable. |
1515 | | */ |
1516 | 0 | preprocess_function_rtes(subroot); |
1517 | | |
1518 | | /* |
1519 | | * Recursively pull up the subquery's subqueries, so that |
1520 | | * pull_up_subqueries' processing is complete for its jointree and |
1521 | | * rangetable. |
1522 | | * |
1523 | | * Note: it's okay that the subquery's recursion starts with NULL for |
1524 | | * containing-join info, even if we are within an outer join in the upper |
1525 | | * query; the lower query starts with a clean slate for outer-join |
1526 | | * semantics. Likewise, we needn't pass down appendrel state. |
1527 | | */ |
1528 | 0 | pull_up_subqueries(subroot); |
1529 | | |
1530 | | /* |
1531 | | * We must flatten any join alias Vars in the subquery's targetlist, |
1532 | | * because pulling up the subquery's subqueries might have changed their |
1533 | | * expansions into arbitrary expressions. That could affect |
1534 | | * pullup_replace_vars' decisions about whether PlaceHolderVar wrappers |
1535 | | * are needed for tlist entries, and if the subquery is LATERAL, the |
1536 | | * expansions might contain lateral references that the is_simple_subquery |
1537 | | * recheck below has to see. The latter also requires flattening join |
1538 | | * alias Vars in the jointree quals of a LATERAL subquery. (Likely it'd |
1539 | | * be better to do flatten_join_alias_vars on the whole query tree at some |
1540 | | * earlier stage, maybe even in the rewriter; but for now let's just fix |
1541 | | * these cases here.) |
1542 | | */ |
1543 | 0 | subquery->targetList = (List *) |
1544 | 0 | flatten_join_alias_vars(subroot, subroot->parse, |
1545 | 0 | (Node *) subquery->targetList); |
1546 | 0 | if (rte->lateral) |
1547 | 0 | flatten_join_alias_vars_in_jointree(subroot, |
1548 | 0 | (Node *) subquery->jointree); |
1549 | | |
1550 | | /* |
1551 | | * Now we must recheck whether the subquery is still simple enough to pull |
1552 | | * up. If not, abandon processing it. |
1553 | | * |
1554 | | * We don't really need to recheck all the conditions involved, but it's |
1555 | | * easier just to keep this "if" looking the same as the one in |
1556 | | * pull_up_subqueries_recurse. |
1557 | | */ |
1558 | 0 | if (is_simple_subquery(root, subquery, rte, lowest_outer_join) && |
1559 | 0 | (containing_appendrel == NULL || is_safe_append_member(subquery))) |
1560 | 0 | { |
1561 | | /* good to go */ |
1562 | 0 | } |
1563 | 0 | else |
1564 | 0 | { |
1565 | | /* |
1566 | | * Give up, return unmodified RangeTblRef. |
1567 | | * |
1568 | | * Note: The work we just did will be redone when the subquery gets |
1569 | | * planned on its own. Perhaps we could avoid that by storing the |
1570 | | * modified subquery back into the rangetable, but I'm not gonna risk |
1571 | | * it now. |
1572 | | */ |
1573 | 0 | return jtnode; |
1574 | 0 | } |
1575 | | |
1576 | | /* |
1577 | | * Adjust level-0 varnos in subquery so that we can append its rangetable |
1578 | | * to upper query's. We have to fix the subquery's append_rel_list as |
1579 | | * well. |
1580 | | */ |
1581 | 0 | rtoffset = list_length(parse->rtable); |
1582 | 0 | OffsetVarNodes((Node *) subquery, rtoffset, 0); |
1583 | 0 | OffsetVarNodes((Node *) subroot->append_rel_list, rtoffset, 0); |
1584 | | |
1585 | | /* |
1586 | | * Upper-level vars in subquery are now one level closer to their parent |
1587 | | * than before. |
1588 | | */ |
1589 | 0 | IncrementVarSublevelsUp((Node *) subquery, -1, 1); |
1590 | 0 | IncrementVarSublevelsUp((Node *) subroot->append_rel_list, -1, 1); |
1591 | | |
1592 | | /* |
1593 | | * The subquery's targetlist items are now in the appropriate form to |
1594 | | * insert into the top query, except that we may need to wrap them in |
1595 | | * PlaceHolderVars. Set up required context data for pullup_replace_vars. |
1596 | | * (Note that we should include the subquery's inner joins in relids, |
1597 | | * since it may include join alias vars referencing them.) |
1598 | | */ |
1599 | 0 | rvcontext.root = root; |
1600 | 0 | rvcontext.targetlist = subquery->targetList; |
1601 | 0 | rvcontext.target_rte = rte; |
1602 | 0 | rvcontext.result_relation = 0; |
1603 | 0 | if (rte->lateral) |
1604 | 0 | { |
1605 | 0 | rvcontext.relids = get_relids_in_jointree((Node *) subquery->jointree, |
1606 | 0 | true, true); |
1607 | 0 | rvcontext.nullinfo = get_nullingrels(parse); |
1608 | 0 | } |
1609 | 0 | else /* won't need these values */ |
1610 | 0 | { |
1611 | 0 | rvcontext.relids = NULL; |
1612 | 0 | rvcontext.nullinfo = NULL; |
1613 | 0 | } |
1614 | 0 | rvcontext.outer_hasSubLinks = &parse->hasSubLinks; |
1615 | 0 | rvcontext.varno = varno; |
1616 | | /* this flag will be set below, if needed */ |
1617 | 0 | rvcontext.wrap_option = REPLACE_WRAP_NONE; |
1618 | | /* initialize cache array with indexes 0 .. length(tlist) */ |
1619 | 0 | rvcontext.rv_cache = palloc0_array(Node *, list_length(subquery->targetList) + 1); |
1620 | | |
1621 | | /* |
1622 | | * If the parent query uses grouping sets, we need a PlaceHolderVar for |
1623 | | * each expression of the subquery's targetlist items. This ensures that |
1624 | | * expressions retain their separate identity so that they will match |
1625 | | * grouping set columns when appropriate. (It'd be sufficient to wrap |
1626 | | * values used in grouping set columns, and do so only in non-aggregated |
1627 | | * portions of the tlist and havingQual, but that would require a lot of |
1628 | | * infrastructure that pullup_replace_vars hasn't currently got.) |
1629 | | */ |
1630 | 0 | if (parse->groupingSets) |
1631 | 0 | rvcontext.wrap_option = REPLACE_WRAP_ALL; |
1632 | | |
1633 | | /* |
1634 | | * Replace all of the top query's references to the subquery's outputs |
1635 | | * with copies of the adjusted subtlist items, being careful not to |
1636 | | * replace any of the jointree structure. |
1637 | | */ |
1638 | 0 | perform_pullup_replace_vars(root, &rvcontext, |
1639 | 0 | containing_appendrel); |
1640 | | |
1641 | | /* |
1642 | | * If the subquery had a LATERAL marker, propagate that to any of its |
1643 | | * child RTEs that could possibly now contain lateral cross-references. |
1644 | | * The children might or might not contain any actual lateral |
1645 | | * cross-references, but we have to mark the pulled-up child RTEs so that |
1646 | | * later planner stages will check for such. |
1647 | | */ |
1648 | 0 | if (rte->lateral) |
1649 | 0 | { |
1650 | 0 | foreach(lc, subquery->rtable) |
1651 | 0 | { |
1652 | 0 | RangeTblEntry *child_rte = (RangeTblEntry *) lfirst(lc); |
1653 | |
|
1654 | 0 | switch (child_rte->rtekind) |
1655 | 0 | { |
1656 | 0 | case RTE_RELATION: |
1657 | 0 | if (child_rte->tablesample) |
1658 | 0 | child_rte->lateral = true; |
1659 | 0 | break; |
1660 | 0 | case RTE_SUBQUERY: |
1661 | 0 | case RTE_FUNCTION: |
1662 | 0 | case RTE_VALUES: |
1663 | 0 | case RTE_TABLEFUNC: |
1664 | 0 | child_rte->lateral = true; |
1665 | 0 | break; |
1666 | 0 | case RTE_JOIN: |
1667 | 0 | case RTE_CTE: |
1668 | 0 | case RTE_NAMEDTUPLESTORE: |
1669 | 0 | case RTE_RESULT: |
1670 | 0 | case RTE_GROUP: |
1671 | | /* these can't contain any lateral references */ |
1672 | 0 | break; |
1673 | 0 | } |
1674 | 0 | } |
1675 | 0 | } |
1676 | | |
1677 | | /* |
1678 | | * Now append the adjusted rtable entries and their perminfos to upper |
1679 | | * query. (We hold off until after fixing the upper rtable entries; no |
1680 | | * point in running that code on the subquery ones too.) |
1681 | | */ |
1682 | 0 | CombineRangeTables(&parse->rtable, &parse->rteperminfos, |
1683 | 0 | subquery->rtable, subquery->rteperminfos); |
1684 | | |
1685 | | /* |
1686 | | * Pull up any FOR UPDATE/SHARE markers, too. (OffsetVarNodes already |
1687 | | * adjusted the marker rtindexes, so just concat the lists.) |
1688 | | */ |
1689 | 0 | parse->rowMarks = list_concat(parse->rowMarks, subquery->rowMarks); |
1690 | | |
1691 | | /* |
1692 | | * We also have to fix the relid sets of any PlaceHolderVar nodes in the |
1693 | | * parent query. (This could perhaps be done by pullup_replace_vars(), |
1694 | | * but it seems cleaner to use two passes.) Note in particular that any |
1695 | | * PlaceHolderVar nodes just created by pullup_replace_vars() will be |
1696 | | * adjusted, so having created them with the subquery's varno is correct. |
1697 | | * |
1698 | | * Likewise, relids appearing in AppendRelInfo nodes have to be fixed. We |
1699 | | * already checked that this won't require introducing multiple subrelids |
1700 | | * into the single-slot AppendRelInfo structs. |
1701 | | */ |
1702 | 0 | if (root->glob->lastPHId != 0 || root->append_rel_list) |
1703 | 0 | { |
1704 | 0 | Relids subrelids; |
1705 | |
|
1706 | 0 | subrelids = get_relids_in_jointree((Node *) subquery->jointree, |
1707 | 0 | true, false); |
1708 | 0 | if (root->glob->lastPHId != 0) |
1709 | 0 | substitute_phv_relids((Node *) parse, varno, subrelids); |
1710 | 0 | fix_append_rel_relids(root, varno, subrelids); |
1711 | 0 | } |
1712 | | |
1713 | | /* |
1714 | | * And now add subquery's AppendRelInfos to our list. |
1715 | | */ |
1716 | 0 | root->append_rel_list = list_concat(root->append_rel_list, |
1717 | 0 | subroot->append_rel_list); |
1718 | | |
1719 | | /* |
1720 | | * We don't have to do the equivalent bookkeeping for outer-join info, |
1721 | | * because that hasn't been set up yet. placeholder_list likewise. |
1722 | | */ |
1723 | 0 | Assert(root->join_info_list == NIL); |
1724 | 0 | Assert(subroot->join_info_list == NIL); |
1725 | 0 | Assert(root->placeholder_list == NIL); |
1726 | 0 | Assert(subroot->placeholder_list == NIL); |
1727 | | |
1728 | | /* |
1729 | | * We no longer need the RTE's copy of the subquery's query tree. Getting |
1730 | | * rid of it saves nothing in particular so far as this level of query is |
1731 | | * concerned; but if this query level is in turn pulled up into a parent, |
1732 | | * we'd waste cycles copying the now-unused query tree. |
1733 | | */ |
1734 | 0 | rte->subquery = NULL; |
1735 | | |
1736 | | /* |
1737 | | * Miscellaneous housekeeping. |
1738 | | * |
1739 | | * Although replace_rte_variables() faithfully updated parse->hasSubLinks |
1740 | | * if it copied any SubLinks out of the subquery's targetlist, we still |
1741 | | * could have SubLinks added to the query in the expressions of FUNCTION |
1742 | | * and VALUES RTEs copied up from the subquery. So it's necessary to copy |
1743 | | * subquery->hasSubLinks anyway. Perhaps this can be improved someday. |
1744 | | */ |
1745 | 0 | parse->hasSubLinks |= subquery->hasSubLinks; |
1746 | | |
1747 | | /* If subquery had any RLS conditions, now main query does too */ |
1748 | 0 | parse->hasRowSecurity |= subquery->hasRowSecurity; |
1749 | | |
1750 | | /* |
1751 | | * subquery won't be pulled up if it hasAggs, hasWindowFuncs, or |
1752 | | * hasTargetSRFs, so no work needed on those flags |
1753 | | */ |
1754 | | |
1755 | | /* |
1756 | | * Return the adjusted subquery jointree to replace the RangeTblRef entry |
1757 | | * in parent's jointree; or, if the FromExpr is degenerate, just return |
1758 | | * its single member. |
1759 | | */ |
1760 | 0 | Assert(IsA(subquery->jointree, FromExpr)); |
1761 | 0 | Assert(subquery->jointree->fromlist != NIL); |
1762 | 0 | if (subquery->jointree->quals == NULL && |
1763 | 0 | list_length(subquery->jointree->fromlist) == 1) |
1764 | 0 | return (Node *) linitial(subquery->jointree->fromlist); |
1765 | | |
1766 | 0 | return (Node *) subquery->jointree; |
1767 | 0 | } |
1768 | | |
1769 | | /* |
1770 | | * pull_up_simple_union_all |
1771 | | * Pull up a single simple UNION ALL subquery. |
1772 | | * |
1773 | | * jtnode is a RangeTblRef that has been identified as a simple UNION ALL |
1774 | | * subquery by pull_up_subqueries. We pull up the leaf subqueries and |
1775 | | * build an "append relation" for the union set. The result value is just |
1776 | | * jtnode, since we don't actually need to change the query jointree. |
1777 | | */ |
1778 | | static Node * |
1779 | | pull_up_simple_union_all(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte) |
1780 | 0 | { |
1781 | 0 | int varno = ((RangeTblRef *) jtnode)->rtindex; |
1782 | 0 | Query *subquery = rte->subquery; |
1783 | 0 | int rtoffset = list_length(root->parse->rtable); |
1784 | 0 | List *rtable; |
1785 | | |
1786 | | /* |
1787 | | * Make a modifiable copy of the subquery's rtable, so we can adjust |
1788 | | * upper-level Vars in it. There are no such Vars in the setOperations |
1789 | | * tree proper, so fixing the rtable should be sufficient. |
1790 | | */ |
1791 | 0 | rtable = copyObject(subquery->rtable); |
1792 | | |
1793 | | /* |
1794 | | * Upper-level vars in subquery are now one level closer to their parent |
1795 | | * than before. We don't have to worry about offsetting varnos, though, |
1796 | | * because the UNION leaf queries can't cross-reference each other. |
1797 | | */ |
1798 | 0 | IncrementVarSublevelsUp_rtable(rtable, -1, 1); |
1799 | | |
1800 | | /* |
1801 | | * If the UNION ALL subquery had a LATERAL marker, propagate that to all |
1802 | | * its children. The individual children might or might not contain any |
1803 | | * actual lateral cross-references, but we have to mark the pulled-up |
1804 | | * child RTEs so that later planner stages will check for such. |
1805 | | */ |
1806 | 0 | if (rte->lateral) |
1807 | 0 | { |
1808 | 0 | ListCell *rt; |
1809 | |
|
1810 | 0 | foreach(rt, rtable) |
1811 | 0 | { |
1812 | 0 | RangeTblEntry *child_rte = (RangeTblEntry *) lfirst(rt); |
1813 | |
|
1814 | 0 | Assert(child_rte->rtekind == RTE_SUBQUERY); |
1815 | 0 | child_rte->lateral = true; |
1816 | 0 | } |
1817 | 0 | } |
1818 | | |
1819 | | /* |
1820 | | * Append child RTEs (and their perminfos) to parent rtable. |
1821 | | */ |
1822 | 0 | CombineRangeTables(&root->parse->rtable, &root->parse->rteperminfos, |
1823 | 0 | rtable, subquery->rteperminfos); |
1824 | | |
1825 | | /* |
1826 | | * Recursively scan the subquery's setOperations tree and add |
1827 | | * AppendRelInfo nodes for leaf subqueries to the parent's |
1828 | | * append_rel_list. Also apply pull_up_subqueries to the leaf subqueries. |
1829 | | */ |
1830 | 0 | Assert(subquery->setOperations); |
1831 | 0 | pull_up_union_leaf_queries(subquery->setOperations, root, varno, subquery, |
1832 | 0 | rtoffset); |
1833 | | |
1834 | | /* |
1835 | | * Mark the parent as an append relation. |
1836 | | */ |
1837 | 0 | rte->inh = true; |
1838 | |
|
1839 | 0 | return jtnode; |
1840 | 0 | } |
1841 | | |
1842 | | /* |
1843 | | * pull_up_union_leaf_queries -- recursive guts of pull_up_simple_union_all |
1844 | | * |
1845 | | * Build an AppendRelInfo for each leaf query in the setop tree, and then |
1846 | | * apply pull_up_subqueries to the leaf query. |
1847 | | * |
1848 | | * Note that setOpQuery is the Query containing the setOp node, whose tlist |
1849 | | * contains references to all the setop output columns. When called from |
1850 | | * pull_up_simple_union_all, this is *not* the same as root->parse, which is |
1851 | | * the parent Query we are pulling up into. |
1852 | | * |
1853 | | * parentRTindex is the appendrel parent's index in root->parse->rtable. |
1854 | | * |
1855 | | * The child RTEs have already been copied to the parent. childRToffset |
1856 | | * tells us where in the parent's range table they were copied. When called |
1857 | | * from flatten_simple_union_all, childRToffset is 0 since the child RTEs |
1858 | | * were already in root->parse->rtable and no RT index adjustment is needed. |
1859 | | */ |
1860 | | static void |
1861 | | pull_up_union_leaf_queries(Node *setOp, PlannerInfo *root, int parentRTindex, |
1862 | | Query *setOpQuery, int childRToffset) |
1863 | 0 | { |
1864 | 0 | if (IsA(setOp, RangeTblRef)) |
1865 | 0 | { |
1866 | 0 | RangeTblRef *rtr = (RangeTblRef *) setOp; |
1867 | 0 | int childRTindex; |
1868 | 0 | AppendRelInfo *appinfo; |
1869 | | |
1870 | | /* |
1871 | | * Calculate the index in the parent's range table |
1872 | | */ |
1873 | 0 | childRTindex = childRToffset + rtr->rtindex; |
1874 | | |
1875 | | /* |
1876 | | * Build a suitable AppendRelInfo, and attach to parent's list. |
1877 | | */ |
1878 | 0 | appinfo = makeNode(AppendRelInfo); |
1879 | 0 | appinfo->parent_relid = parentRTindex; |
1880 | 0 | appinfo->child_relid = childRTindex; |
1881 | 0 | appinfo->parent_reltype = InvalidOid; |
1882 | 0 | appinfo->child_reltype = InvalidOid; |
1883 | 0 | make_setop_translation_list(setOpQuery, childRTindex, appinfo); |
1884 | 0 | appinfo->parent_reloid = InvalidOid; |
1885 | 0 | root->append_rel_list = lappend(root->append_rel_list, appinfo); |
1886 | | |
1887 | | /* |
1888 | | * Recursively apply pull_up_subqueries to the new child RTE. (We |
1889 | | * must build the AppendRelInfo first, because this will modify it; |
1890 | | * indeed, that's the only part of the upper query where Vars |
1891 | | * referencing childRTindex can exist at this point.) |
1892 | | * |
1893 | | * Note that we can pass NULL for containing-join info even if we're |
1894 | | * actually under an outer join, because the child's expressions |
1895 | | * aren't going to propagate up to the join. Also, we ignore the |
1896 | | * possibility that pull_up_subqueries_recurse() returns a different |
1897 | | * jointree node than what we pass it; if it does, the important thing |
1898 | | * is that it replaced the child relid in the AppendRelInfo node. |
1899 | | */ |
1900 | 0 | rtr = makeNode(RangeTblRef); |
1901 | 0 | rtr->rtindex = childRTindex; |
1902 | 0 | (void) pull_up_subqueries_recurse(root, (Node *) rtr, |
1903 | 0 | NULL, appinfo); |
1904 | 0 | } |
1905 | 0 | else if (IsA(setOp, SetOperationStmt)) |
1906 | 0 | { |
1907 | 0 | SetOperationStmt *op = (SetOperationStmt *) setOp; |
1908 | | |
1909 | | /* Recurse to reach leaf queries */ |
1910 | 0 | pull_up_union_leaf_queries(op->larg, root, parentRTindex, setOpQuery, |
1911 | 0 | childRToffset); |
1912 | 0 | pull_up_union_leaf_queries(op->rarg, root, parentRTindex, setOpQuery, |
1913 | 0 | childRToffset); |
1914 | 0 | } |
1915 | 0 | else |
1916 | 0 | { |
1917 | 0 | elog(ERROR, "unrecognized node type: %d", |
1918 | 0 | (int) nodeTag(setOp)); |
1919 | 0 | } |
1920 | 0 | } |
1921 | | |
1922 | | /* |
1923 | | * make_setop_translation_list |
1924 | | * Build the list of translations from parent Vars to child Vars for |
1925 | | * a UNION ALL member. (At this point it's just a simple list of |
1926 | | * referencing Vars, but if we succeed in pulling up the member |
1927 | | * subquery, the Vars will get replaced by pulled-up expressions.) |
1928 | | * Also create the rather trivial reverse-translation array. |
1929 | | */ |
1930 | | static void |
1931 | | make_setop_translation_list(Query *query, int newvarno, |
1932 | | AppendRelInfo *appinfo) |
1933 | 0 | { |
1934 | 0 | List *vars = NIL; |
1935 | 0 | AttrNumber *pcolnos; |
1936 | 0 | ListCell *l; |
1937 | | |
1938 | | /* Initialize reverse-translation array with all entries zero */ |
1939 | | /* (entries for resjunk columns will stay that way) */ |
1940 | 0 | appinfo->num_child_cols = list_length(query->targetList); |
1941 | 0 | appinfo->parent_colnos = pcolnos = palloc0_array(AttrNumber, appinfo->num_child_cols); |
1942 | |
|
1943 | 0 | foreach(l, query->targetList) |
1944 | 0 | { |
1945 | 0 | TargetEntry *tle = (TargetEntry *) lfirst(l); |
1946 | |
|
1947 | 0 | if (tle->resjunk) |
1948 | 0 | continue; |
1949 | | |
1950 | 0 | vars = lappend(vars, makeVarFromTargetEntry(newvarno, tle)); |
1951 | 0 | pcolnos[tle->resno - 1] = tle->resno; |
1952 | 0 | } |
1953 | |
|
1954 | 0 | appinfo->translated_vars = vars; |
1955 | 0 | } |
1956 | | |
1957 | | /* |
1958 | | * is_simple_subquery |
1959 | | * Check a subquery in the range table to see if it's simple enough |
1960 | | * to pull up into the parent query. |
1961 | | * |
1962 | | * rte is the RTE_SUBQUERY RangeTblEntry that contained the subquery. |
1963 | | * (Note subquery is not necessarily equal to rte->subquery; it could be a |
1964 | | * processed copy of that.) |
1965 | | * lowest_outer_join is the lowest outer join above the subquery, or NULL. |
1966 | | */ |
1967 | | static bool |
1968 | | is_simple_subquery(PlannerInfo *root, Query *subquery, RangeTblEntry *rte, |
1969 | | JoinExpr *lowest_outer_join) |
1970 | 0 | { |
1971 | | /* |
1972 | | * Let's just make sure it's a valid subselect ... |
1973 | | */ |
1974 | 0 | if (!IsA(subquery, Query) || |
1975 | 0 | subquery->commandType != CMD_SELECT) |
1976 | 0 | elog(ERROR, "subquery is bogus"); |
1977 | | |
1978 | | /* |
1979 | | * Can't currently pull up a query with setops (unless it's simple UNION |
1980 | | * ALL, which is handled by a different code path). Maybe after querytree |
1981 | | * redesign... |
1982 | | */ |
1983 | 0 | if (subquery->setOperations) |
1984 | 0 | return false; |
1985 | | |
1986 | | /* |
1987 | | * Can't pull up a subquery involving grouping, aggregation, SRFs, |
1988 | | * sorting, limiting, or WITH. (XXX WITH could possibly be allowed later) |
1989 | | * |
1990 | | * We also don't pull up a subquery that has explicit FOR UPDATE/SHARE |
1991 | | * clauses, because pullup would cause the locking to occur semantically |
1992 | | * higher than it should. Implicit FOR UPDATE/SHARE is okay because in |
1993 | | * that case the locking was originally declared in the upper query |
1994 | | * anyway. |
1995 | | */ |
1996 | 0 | if (subquery->hasAggs || |
1997 | 0 | subquery->hasWindowFuncs || |
1998 | 0 | subquery->hasTargetSRFs || |
1999 | 0 | subquery->groupClause || |
2000 | 0 | subquery->groupingSets || |
2001 | 0 | subquery->havingQual || |
2002 | 0 | subquery->sortClause || |
2003 | 0 | subquery->distinctClause || |
2004 | 0 | subquery->limitOffset || |
2005 | 0 | subquery->limitCount || |
2006 | 0 | subquery->hasForUpdate || |
2007 | 0 | subquery->cteList) |
2008 | 0 | return false; |
2009 | | |
2010 | | /* |
2011 | | * Don't pull up if the RTE represents a security-barrier view; we |
2012 | | * couldn't prevent information leakage once the RTE's Vars are scattered |
2013 | | * about in the upper query. |
2014 | | */ |
2015 | 0 | if (rte->security_barrier) |
2016 | 0 | return false; |
2017 | | |
2018 | | /* |
2019 | | * If the subquery is LATERAL, check for pullup restrictions from that. |
2020 | | */ |
2021 | 0 | if (rte->lateral) |
2022 | 0 | { |
2023 | 0 | bool restricted; |
2024 | 0 | Relids safe_upper_varnos; |
2025 | | |
2026 | | /* |
2027 | | * The subquery's WHERE and JOIN/ON quals mustn't contain any lateral |
2028 | | * references to rels outside a higher outer join (including the case |
2029 | | * where the outer join is within the subquery itself). In such a |
2030 | | * case, pulling up would result in a situation where we need to |
2031 | | * postpone quals from below an outer join to above it, which is |
2032 | | * probably completely wrong and in any case is a complication that |
2033 | | * doesn't seem worth addressing at the moment. |
2034 | | */ |
2035 | 0 | if (lowest_outer_join != NULL) |
2036 | 0 | { |
2037 | 0 | restricted = true; |
2038 | 0 | safe_upper_varnos = get_relids_in_jointree((Node *) lowest_outer_join, |
2039 | 0 | true, true); |
2040 | 0 | } |
2041 | 0 | else |
2042 | 0 | { |
2043 | 0 | restricted = false; |
2044 | 0 | safe_upper_varnos = NULL; /* doesn't matter */ |
2045 | 0 | } |
2046 | |
|
2047 | 0 | if (jointree_contains_lateral_outer_refs(root, |
2048 | 0 | (Node *) subquery->jointree, |
2049 | 0 | restricted, safe_upper_varnos)) |
2050 | 0 | return false; |
2051 | | |
2052 | | /* |
2053 | | * If there's an outer join above the LATERAL subquery, also disallow |
2054 | | * pullup if the subquery's targetlist has any references to rels |
2055 | | * outside the outer join, since these might get pulled into quals |
2056 | | * above the subquery (but in or below the outer join) and then lead |
2057 | | * to qual-postponement issues similar to the case checked for above. |
2058 | | * (We wouldn't need to prevent pullup if no such references appear in |
2059 | | * outer-query quals, but we don't have enough info here to check |
2060 | | * that. Also, maybe this restriction could be removed if we forced |
2061 | | * such refs to be wrapped in PlaceHolderVars, even when they're below |
2062 | | * the nearest outer join? But it's a pretty hokey usage, so not |
2063 | | * clear this is worth sweating over.) |
2064 | | * |
2065 | | * If you change this, see also the comments about lateral references |
2066 | | * in pullup_replace_vars_callback(). |
2067 | | */ |
2068 | 0 | if (lowest_outer_join != NULL) |
2069 | 0 | { |
2070 | 0 | Relids lvarnos = pull_varnos_of_level(root, |
2071 | 0 | (Node *) subquery->targetList, |
2072 | 0 | 1); |
2073 | |
|
2074 | 0 | if (!bms_is_subset(lvarnos, safe_upper_varnos)) |
2075 | 0 | return false; |
2076 | 0 | } |
2077 | 0 | } |
2078 | | |
2079 | | /* |
2080 | | * Don't pull up a subquery that has any volatile functions in its |
2081 | | * targetlist. Otherwise we might introduce multiple evaluations of these |
2082 | | * functions, if they get copied to multiple places in the upper query, |
2083 | | * leading to surprising results. (Note: the PlaceHolderVar mechanism |
2084 | | * doesn't quite guarantee single evaluation; else we could pull up anyway |
2085 | | * and just wrap such items in PlaceHolderVars ...) |
2086 | | */ |
2087 | 0 | if (contain_volatile_functions((Node *) subquery->targetList)) |
2088 | 0 | return false; |
2089 | | |
2090 | 0 | return true; |
2091 | 0 | } |
2092 | | |
2093 | | /* |
2094 | | * pull_up_simple_values |
2095 | | * Pull up a single simple VALUES RTE. |
2096 | | * |
2097 | | * jtnode is a RangeTblRef that has been identified as a simple VALUES RTE |
2098 | | * by pull_up_subqueries. We always return a RangeTblRef representing a |
2099 | | * RESULT RTE to replace it (all failure cases should have been detected by |
2100 | | * is_simple_values()). Actually, what we return is just jtnode, because |
2101 | | * we replace the VALUES RTE in the rangetable with the RESULT RTE. |
2102 | | * |
2103 | | * rte is the RangeTblEntry referenced by jtnode. Because of the limited |
2104 | | * possible usage of VALUES RTEs, we do not need the remaining parameters |
2105 | | * of pull_up_subqueries_recurse. |
2106 | | */ |
2107 | | static Node * |
2108 | | pull_up_simple_values(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte) |
2109 | 0 | { |
2110 | 0 | Query *parse = root->parse; |
2111 | 0 | int varno = ((RangeTblRef *) jtnode)->rtindex; |
2112 | 0 | List *values_list; |
2113 | 0 | List *tlist; |
2114 | 0 | AttrNumber attrno; |
2115 | 0 | pullup_replace_vars_context rvcontext; |
2116 | 0 | ListCell *lc; |
2117 | |
|
2118 | 0 | Assert(rte->rtekind == RTE_VALUES); |
2119 | 0 | Assert(list_length(rte->values_lists) == 1); |
2120 | | |
2121 | | /* |
2122 | | * Need a modifiable copy of the VALUES list to hack on, just in case it's |
2123 | | * multiply referenced. |
2124 | | */ |
2125 | 0 | values_list = copyObject(linitial(rte->values_lists)); |
2126 | | |
2127 | | /* |
2128 | | * The VALUES RTE can't contain any Vars of level zero, let alone any that |
2129 | | * are join aliases, so no need to flatten join alias Vars. |
2130 | | */ |
2131 | 0 | Assert(!contain_vars_of_level((Node *) values_list, 0)); |
2132 | | |
2133 | | /* |
2134 | | * Set up required context data for pullup_replace_vars. In particular, |
2135 | | * we have to make the VALUES list look like a subquery targetlist. |
2136 | | */ |
2137 | 0 | tlist = NIL; |
2138 | 0 | attrno = 1; |
2139 | 0 | foreach(lc, values_list) |
2140 | 0 | { |
2141 | 0 | tlist = lappend(tlist, |
2142 | 0 | makeTargetEntry((Expr *) lfirst(lc), |
2143 | 0 | attrno, |
2144 | 0 | NULL, |
2145 | 0 | false)); |
2146 | 0 | attrno++; |
2147 | 0 | } |
2148 | 0 | rvcontext.root = root; |
2149 | 0 | rvcontext.targetlist = tlist; |
2150 | 0 | rvcontext.target_rte = rte; |
2151 | 0 | rvcontext.result_relation = 0; |
2152 | 0 | rvcontext.relids = NULL; /* can't be any lateral references here */ |
2153 | 0 | rvcontext.nullinfo = NULL; |
2154 | 0 | rvcontext.outer_hasSubLinks = &parse->hasSubLinks; |
2155 | 0 | rvcontext.varno = varno; |
2156 | 0 | rvcontext.wrap_option = REPLACE_WRAP_NONE; |
2157 | | /* initialize cache array with indexes 0 .. length(tlist) */ |
2158 | 0 | rvcontext.rv_cache = palloc0_array(Node *, list_length(tlist) + 1); |
2159 | | |
2160 | | /* |
2161 | | * Replace all of the top query's references to the RTE's outputs with |
2162 | | * copies of the adjusted VALUES expressions, being careful not to replace |
2163 | | * any of the jointree structure. We can assume there's no outer joins or |
2164 | | * appendrels in the dummy Query that surrounds a VALUES RTE. |
2165 | | */ |
2166 | 0 | perform_pullup_replace_vars(root, &rvcontext, NULL); |
2167 | | |
2168 | | /* |
2169 | | * There should be no appendrels to fix, nor any outer joins and hence no |
2170 | | * PlaceHolderVars. |
2171 | | */ |
2172 | 0 | Assert(root->append_rel_list == NIL); |
2173 | 0 | Assert(root->join_info_list == NIL); |
2174 | 0 | Assert(root->placeholder_list == NIL); |
2175 | | |
2176 | | /* |
2177 | | * Replace the VALUES RTE with a RESULT RTE. The VALUES RTE is the only |
2178 | | * rtable entry in the current query level, so this is easy. |
2179 | | */ |
2180 | 0 | Assert(list_length(parse->rtable) == 1); |
2181 | | |
2182 | | /* Create suitable RTE */ |
2183 | 0 | rte = makeNode(RangeTblEntry); |
2184 | 0 | rte->rtekind = RTE_RESULT; |
2185 | 0 | rte->eref = makeAlias("*RESULT*", NIL); |
2186 | | |
2187 | | /* Replace rangetable */ |
2188 | 0 | parse->rtable = list_make1(rte); |
2189 | | |
2190 | | /* We could manufacture a new RangeTblRef, but the one we have is fine */ |
2191 | 0 | Assert(varno == 1); |
2192 | |
|
2193 | 0 | return jtnode; |
2194 | 0 | } |
2195 | | |
2196 | | /* |
2197 | | * is_simple_values |
2198 | | * Check a VALUES RTE in the range table to see if it's simple enough |
2199 | | * to pull up into the parent query. |
2200 | | * |
2201 | | * rte is the RTE_VALUES RangeTblEntry to check. |
2202 | | */ |
2203 | | static bool |
2204 | | is_simple_values(PlannerInfo *root, RangeTblEntry *rte) |
2205 | 0 | { |
2206 | 0 | Assert(rte->rtekind == RTE_VALUES); |
2207 | | |
2208 | | /* |
2209 | | * There must be exactly one VALUES list, else it's not semantically |
2210 | | * correct to replace the VALUES RTE with a RESULT RTE, nor would we have |
2211 | | * a unique set of expressions to substitute into the parent query. |
2212 | | */ |
2213 | 0 | if (list_length(rte->values_lists) != 1) |
2214 | 0 | return false; |
2215 | | |
2216 | | /* |
2217 | | * Because VALUES can't appear under an outer join (or at least, we won't |
2218 | | * try to pull it up if it does), we need not worry about LATERAL, nor |
2219 | | * about validity of PHVs for the VALUES' outputs. |
2220 | | */ |
2221 | | |
2222 | | /* |
2223 | | * Don't pull up a VALUES that contains any set-returning or volatile |
2224 | | * functions. The considerations here are basically identical to the |
2225 | | * restrictions on a pull-able subquery's targetlist. |
2226 | | */ |
2227 | 0 | if (expression_returns_set((Node *) rte->values_lists) || |
2228 | 0 | contain_volatile_functions((Node *) rte->values_lists)) |
2229 | 0 | return false; |
2230 | | |
2231 | | /* |
2232 | | * Do not pull up a VALUES that's not the only RTE in its parent query. |
2233 | | * This is actually the only case that the parser will generate at the |
2234 | | * moment, and assuming this is true greatly simplifies |
2235 | | * pull_up_simple_values(). |
2236 | | */ |
2237 | 0 | if (list_length(root->parse->rtable) != 1 || |
2238 | 0 | rte != (RangeTblEntry *) linitial(root->parse->rtable)) |
2239 | 0 | return false; |
2240 | | |
2241 | 0 | return true; |
2242 | 0 | } |
2243 | | |
2244 | | /* |
2245 | | * pull_up_constant_function |
2246 | | * Pull up an RTE_FUNCTION expression that was simplified to a constant. |
2247 | | * |
2248 | | * jtnode is a RangeTblRef that has been identified as a FUNCTION RTE by |
2249 | | * pull_up_subqueries. If its expression is just a Const, hoist that value |
2250 | | * up into the parent query, and replace the RTE_FUNCTION with RTE_RESULT. |
2251 | | * |
2252 | | * In principle we could pull up any immutable expression, but we don't. |
2253 | | * That might result in multiple evaluations of the expression, which could |
2254 | | * be costly if it's not just a Const. Also, the main value of this is |
2255 | | * to let the constant participate in further const-folding, and of course |
2256 | | * that won't happen for a non-Const. |
2257 | | * |
2258 | | * The pulled-up value might need to be wrapped in a PlaceHolderVar if the |
2259 | | * RTE is below an outer join or is part of an appendrel; the extra |
2260 | | * parameters show whether that's needed. |
2261 | | */ |
2262 | | static Node * |
2263 | | pull_up_constant_function(PlannerInfo *root, Node *jtnode, |
2264 | | RangeTblEntry *rte, |
2265 | | AppendRelInfo *containing_appendrel) |
2266 | 0 | { |
2267 | 0 | Query *parse = root->parse; |
2268 | 0 | RangeTblFunction *rtf; |
2269 | 0 | TypeFuncClass functypclass; |
2270 | 0 | Oid funcrettype; |
2271 | 0 | TupleDesc tupdesc; |
2272 | 0 | pullup_replace_vars_context rvcontext; |
2273 | | |
2274 | | /* Fail if the RTE has ORDINALITY - we don't implement that here. */ |
2275 | 0 | if (rte->funcordinality) |
2276 | 0 | return jtnode; |
2277 | | |
2278 | | /* Fail if RTE isn't a single, simple Const expr */ |
2279 | 0 | if (list_length(rte->functions) != 1) |
2280 | 0 | return jtnode; |
2281 | 0 | rtf = linitial_node(RangeTblFunction, rte->functions); |
2282 | 0 | if (!IsA(rtf->funcexpr, Const)) |
2283 | 0 | return jtnode; |
2284 | | |
2285 | | /* |
2286 | | * If the function's result is not a scalar, we punt. In principle we |
2287 | | * could break the composite constant value apart into per-column |
2288 | | * constants, but for now it seems not worth the work. |
2289 | | */ |
2290 | 0 | if (rtf->funccolcount != 1) |
2291 | 0 | return jtnode; /* definitely composite */ |
2292 | | |
2293 | | /* If it has a coldeflist, it certainly returns RECORD */ |
2294 | 0 | if (rtf->funccolnames != NIL) |
2295 | 0 | return jtnode; /* must be a one-column RECORD type */ |
2296 | | |
2297 | 0 | functypclass = get_expr_result_type(rtf->funcexpr, |
2298 | 0 | &funcrettype, |
2299 | 0 | &tupdesc); |
2300 | 0 | if (functypclass != TYPEFUNC_SCALAR) |
2301 | 0 | return jtnode; /* must be a one-column composite type */ |
2302 | | |
2303 | | /* Create context for applying pullup_replace_vars */ |
2304 | 0 | rvcontext.root = root; |
2305 | 0 | rvcontext.targetlist = list_make1(makeTargetEntry((Expr *) rtf->funcexpr, |
2306 | 0 | 1, /* resno */ |
2307 | 0 | NULL, /* resname */ |
2308 | 0 | false)); /* resjunk */ |
2309 | 0 | rvcontext.target_rte = rte; |
2310 | 0 | rvcontext.result_relation = 0; |
2311 | | |
2312 | | /* |
2313 | | * Since this function was reduced to a Const, it doesn't contain any |
2314 | | * lateral references, even if it's marked as LATERAL. This means we |
2315 | | * don't need to fill relids or nullinfo. |
2316 | | */ |
2317 | 0 | rvcontext.relids = NULL; |
2318 | 0 | rvcontext.nullinfo = NULL; |
2319 | |
|
2320 | 0 | rvcontext.outer_hasSubLinks = &parse->hasSubLinks; |
2321 | 0 | rvcontext.varno = ((RangeTblRef *) jtnode)->rtindex; |
2322 | | /* this flag will be set below, if needed */ |
2323 | 0 | rvcontext.wrap_option = REPLACE_WRAP_NONE; |
2324 | | /* initialize cache array with indexes 0 .. length(tlist) */ |
2325 | 0 | rvcontext.rv_cache = palloc0_array(Node *, list_length(rvcontext.targetlist) + 1); |
2326 | | |
2327 | | /* |
2328 | | * If the parent query uses grouping sets, we need a PlaceHolderVar for |
2329 | | * each expression of the subquery's targetlist items. (See comments in |
2330 | | * pull_up_simple_subquery().) |
2331 | | */ |
2332 | 0 | if (parse->groupingSets) |
2333 | 0 | rvcontext.wrap_option = REPLACE_WRAP_ALL; |
2334 | | |
2335 | | /* |
2336 | | * Replace all of the top query's references to the RTE's output with |
2337 | | * copies of the funcexpr, being careful not to replace any of the |
2338 | | * jointree structure. |
2339 | | */ |
2340 | 0 | perform_pullup_replace_vars(root, &rvcontext, |
2341 | 0 | containing_appendrel); |
2342 | | |
2343 | | /* |
2344 | | * We don't need to bother with changing PlaceHolderVars in the parent |
2345 | | * query. Their references to the RT index are still good for now, and |
2346 | | * will get removed later if we're able to drop the RTE_RESULT. |
2347 | | */ |
2348 | | |
2349 | | /* |
2350 | | * Convert the RTE to be RTE_RESULT type, signifying that we don't need to |
2351 | | * scan it anymore, and zero out RTE_FUNCTION-specific fields. Also make |
2352 | | * sure the RTE is not marked LATERAL, since elsewhere we don't expect |
2353 | | * RTE_RESULTs to be LATERAL. |
2354 | | */ |
2355 | 0 | rte->rtekind = RTE_RESULT; |
2356 | 0 | rte->functions = NIL; |
2357 | 0 | rte->lateral = false; |
2358 | | |
2359 | | /* |
2360 | | * We can reuse the RangeTblRef node. |
2361 | | */ |
2362 | 0 | return jtnode; |
2363 | 0 | } |
2364 | | |
2365 | | /* |
2366 | | * is_simple_union_all |
2367 | | * Check a subquery to see if it's a simple UNION ALL. |
2368 | | * |
2369 | | * We require all the setops to be UNION ALL (no mixing) and there can't be |
2370 | | * any datatype coercions involved, ie, all the leaf queries must emit the |
2371 | | * same datatypes. |
2372 | | */ |
2373 | | static bool |
2374 | | is_simple_union_all(Query *subquery) |
2375 | 0 | { |
2376 | 0 | SetOperationStmt *topop; |
2377 | | |
2378 | | /* Let's just make sure it's a valid subselect ... */ |
2379 | 0 | if (!IsA(subquery, Query) || |
2380 | 0 | subquery->commandType != CMD_SELECT) |
2381 | 0 | elog(ERROR, "subquery is bogus"); |
2382 | | |
2383 | | /* Is it a set-operation query at all? */ |
2384 | 0 | topop = castNode(SetOperationStmt, subquery->setOperations); |
2385 | 0 | if (!topop) |
2386 | 0 | return false; |
2387 | | |
2388 | | /* Can't handle ORDER BY, LIMIT/OFFSET, locking, or WITH */ |
2389 | 0 | if (subquery->sortClause || |
2390 | 0 | subquery->limitOffset || |
2391 | 0 | subquery->limitCount || |
2392 | 0 | subquery->rowMarks || |
2393 | 0 | subquery->cteList) |
2394 | 0 | return false; |
2395 | | |
2396 | | /* Recursively check the tree of set operations */ |
2397 | 0 | return is_simple_union_all_recurse((Node *) topop, subquery, |
2398 | 0 | topop->colTypes); |
2399 | 0 | } |
2400 | | |
2401 | | static bool |
2402 | | is_simple_union_all_recurse(Node *setOp, Query *setOpQuery, List *colTypes) |
2403 | 0 | { |
2404 | | /* Since this function recurses, it could be driven to stack overflow. */ |
2405 | 0 | check_stack_depth(); |
2406 | |
|
2407 | 0 | if (IsA(setOp, RangeTblRef)) |
2408 | 0 | { |
2409 | 0 | RangeTblRef *rtr = (RangeTblRef *) setOp; |
2410 | 0 | RangeTblEntry *rte = rt_fetch(rtr->rtindex, setOpQuery->rtable); |
2411 | 0 | Query *subquery = rte->subquery; |
2412 | |
|
2413 | 0 | Assert(subquery != NULL); |
2414 | | |
2415 | | /* Leaf nodes are OK if they match the toplevel column types */ |
2416 | | /* We don't have to compare typmods or collations here */ |
2417 | 0 | return tlist_same_datatypes(subquery->targetList, colTypes, true); |
2418 | 0 | } |
2419 | 0 | else if (IsA(setOp, SetOperationStmt)) |
2420 | 0 | { |
2421 | 0 | SetOperationStmt *op = (SetOperationStmt *) setOp; |
2422 | | |
2423 | | /* Must be UNION ALL */ |
2424 | 0 | if (op->op != SETOP_UNION || !op->all) |
2425 | 0 | return false; |
2426 | | |
2427 | | /* Recurse to check inputs */ |
2428 | 0 | return is_simple_union_all_recurse(op->larg, setOpQuery, colTypes) && |
2429 | 0 | is_simple_union_all_recurse(op->rarg, setOpQuery, colTypes); |
2430 | 0 | } |
2431 | 0 | else |
2432 | 0 | { |
2433 | 0 | elog(ERROR, "unrecognized node type: %d", |
2434 | 0 | (int) nodeTag(setOp)); |
2435 | 0 | return false; /* keep compiler quiet */ |
2436 | 0 | } |
2437 | 0 | } |
2438 | | |
2439 | | /* |
2440 | | * is_safe_append_member |
2441 | | * Check a subquery that is a leaf of a UNION ALL appendrel to see if it's |
2442 | | * safe to pull up. |
2443 | | */ |
2444 | | static bool |
2445 | | is_safe_append_member(Query *subquery) |
2446 | 0 | { |
2447 | 0 | FromExpr *jtnode; |
2448 | | |
2449 | | /* |
2450 | | * It's only safe to pull up the child if its jointree contains exactly |
2451 | | * one RTE, else the AppendRelInfo data structure breaks. The one base RTE |
2452 | | * could be buried in several levels of FromExpr, however. Also, if the |
2453 | | * child's jointree is completely empty, we can pull up because |
2454 | | * pull_up_simple_subquery will insert a single RTE_RESULT RTE instead. |
2455 | | * |
2456 | | * Also, the child can't have any WHERE quals because there's no place to |
2457 | | * put them in an appendrel. (This is a bit annoying...) If we didn't |
2458 | | * need to check this, we'd just test whether get_relids_in_jointree() |
2459 | | * yields a singleton set, to be more consistent with the coding of |
2460 | | * fix_append_rel_relids(). |
2461 | | */ |
2462 | 0 | jtnode = subquery->jointree; |
2463 | 0 | Assert(IsA(jtnode, FromExpr)); |
2464 | | /* Check the completely-empty case */ |
2465 | 0 | if (jtnode->fromlist == NIL && jtnode->quals == NULL) |
2466 | 0 | return true; |
2467 | | /* Check the more general case */ |
2468 | 0 | while (IsA(jtnode, FromExpr)) |
2469 | 0 | { |
2470 | 0 | if (jtnode->quals != NULL) |
2471 | 0 | return false; |
2472 | 0 | if (list_length(jtnode->fromlist) != 1) |
2473 | 0 | return false; |
2474 | 0 | jtnode = linitial(jtnode->fromlist); |
2475 | 0 | } |
2476 | 0 | if (!IsA(jtnode, RangeTblRef)) |
2477 | 0 | return false; |
2478 | | |
2479 | 0 | return true; |
2480 | 0 | } |
2481 | | |
2482 | | /* |
2483 | | * jointree_contains_lateral_outer_refs |
2484 | | * Check for disallowed lateral references in a jointree's quals |
2485 | | * |
2486 | | * If restricted is false, all level-1 Vars are allowed (but we still must |
2487 | | * search the jointree, since it might contain outer joins below which there |
2488 | | * will be restrictions). If restricted is true, return true when any qual |
2489 | | * in the jointree contains level-1 Vars coming from outside the rels listed |
2490 | | * in safe_upper_varnos. |
2491 | | */ |
2492 | | static bool |
2493 | | jointree_contains_lateral_outer_refs(PlannerInfo *root, Node *jtnode, |
2494 | | bool restricted, |
2495 | | Relids safe_upper_varnos) |
2496 | 0 | { |
2497 | 0 | if (jtnode == NULL) |
2498 | 0 | return false; |
2499 | 0 | if (IsA(jtnode, RangeTblRef)) |
2500 | 0 | return false; |
2501 | 0 | else if (IsA(jtnode, FromExpr)) |
2502 | 0 | { |
2503 | 0 | FromExpr *f = (FromExpr *) jtnode; |
2504 | 0 | ListCell *l; |
2505 | | |
2506 | | /* First, recurse to check child joins */ |
2507 | 0 | foreach(l, f->fromlist) |
2508 | 0 | { |
2509 | 0 | if (jointree_contains_lateral_outer_refs(root, |
2510 | 0 | lfirst(l), |
2511 | 0 | restricted, |
2512 | 0 | safe_upper_varnos)) |
2513 | 0 | return true; |
2514 | 0 | } |
2515 | | |
2516 | | /* Then check the top-level quals */ |
2517 | 0 | if (restricted && |
2518 | 0 | !bms_is_subset(pull_varnos_of_level(root, f->quals, 1), |
2519 | 0 | safe_upper_varnos)) |
2520 | 0 | return true; |
2521 | 0 | } |
2522 | 0 | else if (IsA(jtnode, JoinExpr)) |
2523 | 0 | { |
2524 | 0 | JoinExpr *j = (JoinExpr *) jtnode; |
2525 | | |
2526 | | /* |
2527 | | * If this is an outer join, we mustn't allow any upper lateral |
2528 | | * references in or below it. |
2529 | | */ |
2530 | 0 | if (j->jointype != JOIN_INNER) |
2531 | 0 | { |
2532 | 0 | restricted = true; |
2533 | 0 | safe_upper_varnos = NULL; |
2534 | 0 | } |
2535 | | |
2536 | | /* Check the child joins */ |
2537 | 0 | if (jointree_contains_lateral_outer_refs(root, |
2538 | 0 | j->larg, |
2539 | 0 | restricted, |
2540 | 0 | safe_upper_varnos)) |
2541 | 0 | return true; |
2542 | 0 | if (jointree_contains_lateral_outer_refs(root, |
2543 | 0 | j->rarg, |
2544 | 0 | restricted, |
2545 | 0 | safe_upper_varnos)) |
2546 | 0 | return true; |
2547 | | |
2548 | | /* Check the JOIN's qual clauses */ |
2549 | 0 | if (restricted && |
2550 | 0 | !bms_is_subset(pull_varnos_of_level(root, j->quals, 1), |
2551 | 0 | safe_upper_varnos)) |
2552 | 0 | return true; |
2553 | 0 | } |
2554 | 0 | else |
2555 | 0 | elog(ERROR, "unrecognized node type: %d", |
2556 | 0 | (int) nodeTag(jtnode)); |
2557 | 0 | return false; |
2558 | 0 | } |
2559 | | |
2560 | | /* |
2561 | | * flatten_join_alias_vars_in_jointree |
2562 | | * Apply flatten_join_alias_vars to all quals in the given jointree, |
2563 | | * replacing them in place. The jointree must belong to root->parse. |
2564 | | */ |
2565 | | static void |
2566 | | flatten_join_alias_vars_in_jointree(PlannerInfo *root, Node *jtnode) |
2567 | 0 | { |
2568 | 0 | if (jtnode == NULL) |
2569 | 0 | return; |
2570 | 0 | if (IsA(jtnode, RangeTblRef)) |
2571 | 0 | return; |
2572 | 0 | else if (IsA(jtnode, FromExpr)) |
2573 | 0 | { |
2574 | 0 | FromExpr *f = (FromExpr *) jtnode; |
2575 | 0 | ListCell *l; |
2576 | |
|
2577 | 0 | foreach(l, f->fromlist) |
2578 | 0 | flatten_join_alias_vars_in_jointree(root, lfirst(l)); |
2579 | 0 | f->quals = flatten_join_alias_vars(root, root->parse, f->quals); |
2580 | 0 | } |
2581 | 0 | else if (IsA(jtnode, JoinExpr)) |
2582 | 0 | { |
2583 | 0 | JoinExpr *j = (JoinExpr *) jtnode; |
2584 | |
|
2585 | 0 | flatten_join_alias_vars_in_jointree(root, j->larg); |
2586 | 0 | flatten_join_alias_vars_in_jointree(root, j->rarg); |
2587 | 0 | j->quals = flatten_join_alias_vars(root, root->parse, j->quals); |
2588 | 0 | } |
2589 | 0 | else |
2590 | 0 | elog(ERROR, "unrecognized node type: %d", |
2591 | 0 | (int) nodeTag(jtnode)); |
2592 | 0 | } |
2593 | | |
2594 | | /* |
2595 | | * Perform pullup_replace_vars everyplace it's needed in the query tree. |
2596 | | * |
2597 | | * Caller has already filled *rvcontext with data describing what to |
2598 | | * substitute for Vars referencing the target subquery. In addition |
2599 | | * we need the identity of the containing appendrel if any. |
2600 | | */ |
2601 | | static void |
2602 | | perform_pullup_replace_vars(PlannerInfo *root, |
2603 | | pullup_replace_vars_context *rvcontext, |
2604 | | AppendRelInfo *containing_appendrel) |
2605 | 0 | { |
2606 | 0 | Query *parse = root->parse; |
2607 | 0 | ListCell *lc; |
2608 | | |
2609 | | /* |
2610 | | * If we are considering an appendrel child subquery (that is, a UNION ALL |
2611 | | * member query that we're pulling up), then the only part of the upper |
2612 | | * query that could reference the child yet is the translated_vars list of |
2613 | | * the associated AppendRelInfo. Furthermore, we do not want to force use |
2614 | | * of PHVs in the AppendRelInfo --- there isn't any outer join between. |
2615 | | */ |
2616 | 0 | if (containing_appendrel) |
2617 | 0 | { |
2618 | 0 | ReplaceWrapOption save_wrap_option = rvcontext->wrap_option; |
2619 | |
|
2620 | 0 | rvcontext->wrap_option = REPLACE_WRAP_NONE; |
2621 | 0 | containing_appendrel->translated_vars = (List *) |
2622 | 0 | pullup_replace_vars((Node *) containing_appendrel->translated_vars, |
2623 | 0 | rvcontext); |
2624 | 0 | rvcontext->wrap_option = save_wrap_option; |
2625 | 0 | return; |
2626 | 0 | } |
2627 | | |
2628 | | /* |
2629 | | * Replace all of the top query's references to the subquery's outputs |
2630 | | * with copies of the adjusted subtlist items, being careful not to |
2631 | | * replace any of the jointree structure. (This'd be a lot cleaner if we |
2632 | | * could use query_tree_mutator.) We have to use PHVs in the targetList, |
2633 | | * returningList, and havingQual, since those are certainly above any |
2634 | | * outer join. replace_vars_in_jointree tracks its location in the |
2635 | | * jointree and uses PHVs or not appropriately. |
2636 | | */ |
2637 | 0 | parse->targetList = (List *) |
2638 | 0 | pullup_replace_vars((Node *) parse->targetList, rvcontext); |
2639 | 0 | parse->returningList = (List *) |
2640 | 0 | pullup_replace_vars((Node *) parse->returningList, rvcontext); |
2641 | |
|
2642 | 0 | if (parse->onConflict) |
2643 | 0 | { |
2644 | 0 | parse->onConflict->onConflictSet = (List *) |
2645 | 0 | pullup_replace_vars((Node *) parse->onConflict->onConflictSet, |
2646 | 0 | rvcontext); |
2647 | 0 | parse->onConflict->onConflictWhere = |
2648 | 0 | pullup_replace_vars(parse->onConflict->onConflictWhere, |
2649 | 0 | rvcontext); |
2650 | | |
2651 | | /* |
2652 | | * We assume ON CONFLICT's arbiterElems, arbiterWhere, exclRelTlist |
2653 | | * can't contain any references to a subquery. |
2654 | | */ |
2655 | 0 | } |
2656 | 0 | if (parse->mergeActionList) |
2657 | 0 | { |
2658 | 0 | foreach(lc, parse->mergeActionList) |
2659 | 0 | { |
2660 | 0 | MergeAction *action = lfirst(lc); |
2661 | |
|
2662 | 0 | action->qual = pullup_replace_vars(action->qual, rvcontext); |
2663 | 0 | action->targetList = (List *) |
2664 | 0 | pullup_replace_vars((Node *) action->targetList, rvcontext); |
2665 | 0 | } |
2666 | 0 | } |
2667 | 0 | parse->mergeJoinCondition = pullup_replace_vars(parse->mergeJoinCondition, |
2668 | 0 | rvcontext); |
2669 | 0 | replace_vars_in_jointree((Node *) parse->jointree, rvcontext); |
2670 | 0 | Assert(parse->setOperations == NULL); |
2671 | 0 | parse->havingQual = pullup_replace_vars(parse->havingQual, rvcontext); |
2672 | | |
2673 | | /* |
2674 | | * Replace references in the translated_vars lists of appendrels. |
2675 | | */ |
2676 | 0 | foreach(lc, root->append_rel_list) |
2677 | 0 | { |
2678 | 0 | AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(lc); |
2679 | |
|
2680 | 0 | appinfo->translated_vars = (List *) |
2681 | 0 | pullup_replace_vars((Node *) appinfo->translated_vars, rvcontext); |
2682 | 0 | } |
2683 | | |
2684 | | /* |
2685 | | * Replace references in the joinaliasvars lists of join RTEs and the |
2686 | | * groupexprs list of group RTE. |
2687 | | */ |
2688 | 0 | foreach(lc, parse->rtable) |
2689 | 0 | { |
2690 | 0 | RangeTblEntry *otherrte = (RangeTblEntry *) lfirst(lc); |
2691 | |
|
2692 | 0 | if (otherrte->rtekind == RTE_JOIN) |
2693 | 0 | otherrte->joinaliasvars = (List *) |
2694 | 0 | pullup_replace_vars((Node *) otherrte->joinaliasvars, |
2695 | 0 | rvcontext); |
2696 | 0 | else if (otherrte->rtekind == RTE_GROUP) |
2697 | 0 | otherrte->groupexprs = (List *) |
2698 | 0 | pullup_replace_vars((Node *) otherrte->groupexprs, |
2699 | 0 | rvcontext); |
2700 | 0 | } |
2701 | 0 | } |
2702 | | |
2703 | | /* |
2704 | | * Helper routine for perform_pullup_replace_vars: do pullup_replace_vars on |
2705 | | * every expression in the jointree, without changing the jointree structure |
2706 | | * itself. Ugly, but there's no other way... |
2707 | | */ |
2708 | | static void |
2709 | | replace_vars_in_jointree(Node *jtnode, |
2710 | | pullup_replace_vars_context *context) |
2711 | 0 | { |
2712 | 0 | if (jtnode == NULL) |
2713 | 0 | return; |
2714 | 0 | if (IsA(jtnode, RangeTblRef)) |
2715 | 0 | { |
2716 | | /* |
2717 | | * If the RangeTblRef refers to a LATERAL subquery (that isn't the |
2718 | | * same subquery we're pulling up), it might contain references to the |
2719 | | * target subquery, which we must replace. We drive this from the |
2720 | | * jointree scan, rather than a scan of the rtable, so that we can |
2721 | | * avoid processing no-longer-referenced RTEs. |
2722 | | */ |
2723 | 0 | int varno = ((RangeTblRef *) jtnode)->rtindex; |
2724 | |
|
2725 | 0 | if (varno != context->varno) /* ignore target subquery itself */ |
2726 | 0 | { |
2727 | 0 | RangeTblEntry *rte = rt_fetch(varno, context->root->parse->rtable); |
2728 | |
|
2729 | 0 | Assert(rte != context->target_rte); |
2730 | 0 | if (rte->lateral) |
2731 | 0 | { |
2732 | 0 | switch (rte->rtekind) |
2733 | 0 | { |
2734 | 0 | case RTE_RELATION: |
2735 | | /* shouldn't be marked LATERAL unless tablesample */ |
2736 | 0 | Assert(rte->tablesample); |
2737 | 0 | rte->tablesample = (TableSampleClause *) |
2738 | 0 | pullup_replace_vars((Node *) rte->tablesample, |
2739 | 0 | context); |
2740 | 0 | break; |
2741 | 0 | case RTE_SUBQUERY: |
2742 | 0 | rte->subquery = |
2743 | 0 | pullup_replace_vars_subquery(rte->subquery, |
2744 | 0 | context); |
2745 | 0 | break; |
2746 | 0 | case RTE_FUNCTION: |
2747 | 0 | rte->functions = (List *) |
2748 | 0 | pullup_replace_vars((Node *) rte->functions, |
2749 | 0 | context); |
2750 | 0 | break; |
2751 | 0 | case RTE_TABLEFUNC: |
2752 | 0 | rte->tablefunc = (TableFunc *) |
2753 | 0 | pullup_replace_vars((Node *) rte->tablefunc, |
2754 | 0 | context); |
2755 | 0 | break; |
2756 | 0 | case RTE_VALUES: |
2757 | 0 | rte->values_lists = (List *) |
2758 | 0 | pullup_replace_vars((Node *) rte->values_lists, |
2759 | 0 | context); |
2760 | 0 | break; |
2761 | 0 | case RTE_JOIN: |
2762 | 0 | case RTE_CTE: |
2763 | 0 | case RTE_NAMEDTUPLESTORE: |
2764 | 0 | case RTE_RESULT: |
2765 | 0 | case RTE_GROUP: |
2766 | | /* these shouldn't be marked LATERAL */ |
2767 | 0 | Assert(false); |
2768 | 0 | break; |
2769 | 0 | } |
2770 | 0 | } |
2771 | 0 | } |
2772 | 0 | } |
2773 | 0 | else if (IsA(jtnode, FromExpr)) |
2774 | 0 | { |
2775 | 0 | FromExpr *f = (FromExpr *) jtnode; |
2776 | 0 | ListCell *l; |
2777 | |
|
2778 | 0 | foreach(l, f->fromlist) |
2779 | 0 | replace_vars_in_jointree(lfirst(l), context); |
2780 | 0 | f->quals = pullup_replace_vars(f->quals, context); |
2781 | 0 | } |
2782 | 0 | else if (IsA(jtnode, JoinExpr)) |
2783 | 0 | { |
2784 | 0 | JoinExpr *j = (JoinExpr *) jtnode; |
2785 | 0 | ReplaceWrapOption save_wrap_option = context->wrap_option; |
2786 | |
|
2787 | 0 | replace_vars_in_jointree(j->larg, context); |
2788 | 0 | replace_vars_in_jointree(j->rarg, context); |
2789 | | |
2790 | | /* |
2791 | | * Use PHVs within the join quals of a full join for variable-free |
2792 | | * expressions. Otherwise, we cannot identify which side of the join |
2793 | | * a pulled-up variable-free expression came from, which can lead to |
2794 | | * failure to make a plan at all because none of the quals appear to |
2795 | | * be mergeable or hashable conditions. |
2796 | | */ |
2797 | 0 | if (j->jointype == JOIN_FULL) |
2798 | 0 | context->wrap_option = REPLACE_WRAP_VARFREE; |
2799 | |
|
2800 | 0 | j->quals = pullup_replace_vars(j->quals, context); |
2801 | |
|
2802 | 0 | context->wrap_option = save_wrap_option; |
2803 | 0 | } |
2804 | 0 | else |
2805 | 0 | elog(ERROR, "unrecognized node type: %d", |
2806 | 0 | (int) nodeTag(jtnode)); |
2807 | 0 | } |
2808 | | |
2809 | | /* |
2810 | | * Apply pullup variable replacement throughout an expression tree |
2811 | | * |
2812 | | * Returns a modified copy of the tree, so this can't be used where we |
2813 | | * need to do in-place replacement. |
2814 | | */ |
2815 | | static Node * |
2816 | | pullup_replace_vars(Node *expr, pullup_replace_vars_context *context) |
2817 | 0 | { |
2818 | 0 | return replace_rte_variables(expr, |
2819 | 0 | context->varno, 0, |
2820 | 0 | pullup_replace_vars_callback, |
2821 | 0 | context, |
2822 | 0 | context->outer_hasSubLinks); |
2823 | 0 | } |
2824 | | |
2825 | | static Node * |
2826 | | pullup_replace_vars_callback(const Var *var, |
2827 | | replace_rte_variables_context *context) |
2828 | 0 | { |
2829 | 0 | pullup_replace_vars_context *rcon = (pullup_replace_vars_context *) context->callback_arg; |
2830 | 0 | int varattno = var->varattno; |
2831 | 0 | bool need_phv; |
2832 | 0 | Node *newnode; |
2833 | | |
2834 | | /* System columns are not replaced. */ |
2835 | 0 | if (varattno < InvalidAttrNumber) |
2836 | 0 | return (Node *) copyObject(var); |
2837 | | |
2838 | | /* |
2839 | | * We need a PlaceHolderVar if the Var-to-be-replaced has nonempty |
2840 | | * varnullingrels (unless we find below that the replacement expression is |
2841 | | * a Var or PlaceHolderVar that we can just add the nullingrels to). We |
2842 | | * also need one if the caller has instructed us that certain expression |
2843 | | * replacements need to be wrapped for identification purposes. |
2844 | | */ |
2845 | 0 | need_phv = (var->varnullingrels != NULL) || |
2846 | 0 | (rcon->wrap_option != REPLACE_WRAP_NONE); |
2847 | | |
2848 | | /* |
2849 | | * If PlaceHolderVars are needed, we cache the modified expressions in |
2850 | | * rcon->rv_cache[]. This is not in hopes of any material speed gain |
2851 | | * within this function, but to avoid generating identical PHVs with |
2852 | | * different IDs. That would result in duplicate evaluations at runtime, |
2853 | | * and possibly prevent optimizations that rely on recognizing different |
2854 | | * references to the same subquery output as being equal(). So it's worth |
2855 | | * a bit of extra effort to avoid it. |
2856 | | * |
2857 | | * The cached items have phlevelsup = 0 and phnullingrels = NULL; we'll |
2858 | | * copy them and adjust those values for this reference site below. |
2859 | | */ |
2860 | 0 | if (need_phv && |
2861 | 0 | varattno >= InvalidAttrNumber && |
2862 | 0 | varattno <= list_length(rcon->targetlist) && |
2863 | 0 | rcon->rv_cache[varattno] != NULL) |
2864 | 0 | { |
2865 | | /* Just copy the entry and fall through to adjust phlevelsup etc */ |
2866 | 0 | newnode = copyObject(rcon->rv_cache[varattno]); |
2867 | 0 | } |
2868 | 0 | else |
2869 | 0 | { |
2870 | | /* |
2871 | | * Generate the replacement expression. This takes care of expanding |
2872 | | * wholerow references and dealing with non-default varreturningtype. |
2873 | | */ |
2874 | 0 | newnode = ReplaceVarFromTargetList(var, |
2875 | 0 | rcon->target_rte, |
2876 | 0 | rcon->targetlist, |
2877 | 0 | rcon->result_relation, |
2878 | 0 | REPLACEVARS_REPORT_ERROR, |
2879 | 0 | 0); |
2880 | | |
2881 | | /* Insert PlaceHolderVar if needed */ |
2882 | 0 | if (need_phv) |
2883 | 0 | { |
2884 | 0 | bool wrap; |
2885 | |
|
2886 | 0 | if (rcon->wrap_option == REPLACE_WRAP_ALL) |
2887 | 0 | { |
2888 | | /* Caller told us to wrap all expressions in a PlaceHolderVar */ |
2889 | 0 | wrap = true; |
2890 | 0 | } |
2891 | 0 | else if (varattno == InvalidAttrNumber) |
2892 | 0 | { |
2893 | | /* |
2894 | | * Insert PlaceHolderVar for whole-tuple reference. Notice |
2895 | | * that we are wrapping one PlaceHolderVar around the whole |
2896 | | * RowExpr, rather than putting one around each element of the |
2897 | | * row. This is because we need the expression to yield NULL, |
2898 | | * not ROW(NULL,NULL,...) when it is forced to null by an |
2899 | | * outer join. |
2900 | | */ |
2901 | 0 | wrap = true; |
2902 | 0 | } |
2903 | 0 | else if (newnode && IsA(newnode, Var) && |
2904 | 0 | ((Var *) newnode)->varlevelsup == 0) |
2905 | 0 | { |
2906 | | /* |
2907 | | * Simple Vars always escape being wrapped, unless they are |
2908 | | * lateral references to something outside the subquery being |
2909 | | * pulled up and the referenced rel is not under the same |
2910 | | * lowest nulling outer join. |
2911 | | */ |
2912 | 0 | wrap = false; |
2913 | 0 | if (rcon->target_rte->lateral && |
2914 | 0 | !bms_is_member(((Var *) newnode)->varno, rcon->relids)) |
2915 | 0 | { |
2916 | 0 | nullingrel_info *nullinfo = rcon->nullinfo; |
2917 | 0 | int lvarno = ((Var *) newnode)->varno; |
2918 | |
|
2919 | 0 | Assert(lvarno > 0 && lvarno <= nullinfo->rtlength); |
2920 | 0 | if (!bms_is_subset(nullinfo->nullingrels[rcon->varno], |
2921 | 0 | nullinfo->nullingrels[lvarno])) |
2922 | 0 | wrap = true; |
2923 | 0 | } |
2924 | 0 | } |
2925 | 0 | else if (newnode && IsA(newnode, PlaceHolderVar) && |
2926 | 0 | ((PlaceHolderVar *) newnode)->phlevelsup == 0) |
2927 | 0 | { |
2928 | | /* The same rules apply for a PlaceHolderVar */ |
2929 | 0 | wrap = false; |
2930 | 0 | if (rcon->target_rte->lateral && |
2931 | 0 | !bms_is_subset(((PlaceHolderVar *) newnode)->phrels, |
2932 | 0 | rcon->relids)) |
2933 | 0 | { |
2934 | 0 | nullingrel_info *nullinfo = rcon->nullinfo; |
2935 | 0 | Relids lvarnos = ((PlaceHolderVar *) newnode)->phrels; |
2936 | 0 | int lvarno; |
2937 | |
|
2938 | 0 | lvarno = -1; |
2939 | 0 | while ((lvarno = bms_next_member(lvarnos, lvarno)) >= 0) |
2940 | 0 | { |
2941 | 0 | Assert(lvarno > 0 && lvarno <= nullinfo->rtlength); |
2942 | 0 | if (!bms_is_subset(nullinfo->nullingrels[rcon->varno], |
2943 | 0 | nullinfo->nullingrels[lvarno])) |
2944 | 0 | { |
2945 | 0 | wrap = true; |
2946 | 0 | break; |
2947 | 0 | } |
2948 | 0 | } |
2949 | 0 | } |
2950 | 0 | } |
2951 | 0 | else |
2952 | 0 | { |
2953 | | /* |
2954 | | * If the node contains Var(s) or PlaceHolderVar(s) of the |
2955 | | * subquery being pulled up, or of rels that are under the |
2956 | | * same lowest nulling outer join as the subquery, and does |
2957 | | * not contain any non-strict constructs, then instead of |
2958 | | * adding a PHV on top we can add the required nullingrels to |
2959 | | * those Vars/PHVs. (This is fundamentally a generalization |
2960 | | * of the above cases for bare Vars and PHVs.) |
2961 | | * |
2962 | | * This test is somewhat expensive, but it avoids pessimizing |
2963 | | * the plan in cases where the nullingrels get removed again |
2964 | | * later by outer join reduction. |
2965 | | * |
2966 | | * Note that we don't force wrapping of expressions containing |
2967 | | * lateral references, so long as they also contain Vars/PHVs |
2968 | | * of the subquery, or of rels that are under the same lowest |
2969 | | * nulling outer join as the subquery. This is okay because |
2970 | | * of the restriction to strict constructs: if those Vars/PHVs |
2971 | | * have been forced to NULL by an outer join then the end |
2972 | | * result of the expression will be NULL too, regardless of |
2973 | | * the lateral references. So it's not necessary to force the |
2974 | | * expression to be evaluated below the outer join. This can |
2975 | | * be a very valuable optimization, because it may allow us to |
2976 | | * avoid using a nested loop to pass the lateral reference |
2977 | | * down. |
2978 | | * |
2979 | | * This analysis could be tighter: in particular, a non-strict |
2980 | | * construct hidden within a lower-level PlaceHolderVar is not |
2981 | | * reason to add another PHV. But for now it doesn't seem |
2982 | | * worth the code to be more exact. This is also why it's |
2983 | | * preferable to handle bare PHVs in the above branch, rather |
2984 | | * than this branch. We also prefer to handle bare Vars in a |
2985 | | * separate branch, as it's cheaper this way and parallels the |
2986 | | * handling of PHVs. |
2987 | | * |
2988 | | * For a LATERAL subquery, we have to check the actual var |
2989 | | * membership of the node, but if it's non-lateral then any |
2990 | | * level-zero var must belong to the subquery. |
2991 | | */ |
2992 | 0 | bool contain_nullable_vars = false; |
2993 | |
|
2994 | 0 | if (!rcon->target_rte->lateral) |
2995 | 0 | { |
2996 | 0 | if (contain_vars_of_level(newnode, 0)) |
2997 | 0 | contain_nullable_vars = true; |
2998 | 0 | } |
2999 | 0 | else |
3000 | 0 | { |
3001 | 0 | Relids all_varnos; |
3002 | |
|
3003 | 0 | all_varnos = pull_varnos(rcon->root, newnode); |
3004 | 0 | if (bms_overlap(all_varnos, rcon->relids)) |
3005 | 0 | contain_nullable_vars = true; |
3006 | 0 | else |
3007 | 0 | { |
3008 | 0 | nullingrel_info *nullinfo = rcon->nullinfo; |
3009 | 0 | int varno; |
3010 | |
|
3011 | 0 | varno = -1; |
3012 | 0 | while ((varno = bms_next_member(all_varnos, varno)) >= 0) |
3013 | 0 | { |
3014 | 0 | Assert(varno > 0 && varno <= nullinfo->rtlength); |
3015 | 0 | if (bms_is_subset(nullinfo->nullingrels[rcon->varno], |
3016 | 0 | nullinfo->nullingrels[varno])) |
3017 | 0 | { |
3018 | 0 | contain_nullable_vars = true; |
3019 | 0 | break; |
3020 | 0 | } |
3021 | 0 | } |
3022 | 0 | } |
3023 | 0 | } |
3024 | |
|
3025 | 0 | if (contain_nullable_vars && |
3026 | 0 | !contain_nonstrict_functions(newnode)) |
3027 | 0 | { |
3028 | | /* No wrap needed */ |
3029 | 0 | wrap = false; |
3030 | 0 | } |
3031 | 0 | else |
3032 | 0 | { |
3033 | | /* Else wrap it in a PlaceHolderVar */ |
3034 | 0 | wrap = true; |
3035 | 0 | } |
3036 | 0 | } |
3037 | |
|
3038 | 0 | if (wrap) |
3039 | 0 | { |
3040 | 0 | newnode = (Node *) |
3041 | 0 | make_placeholder_expr(rcon->root, |
3042 | 0 | (Expr *) newnode, |
3043 | 0 | bms_make_singleton(rcon->varno)); |
3044 | | |
3045 | | /* |
3046 | | * Cache it if possible (ie, if the attno is in range, which |
3047 | | * it probably always should be). |
3048 | | */ |
3049 | 0 | if (varattno >= InvalidAttrNumber && |
3050 | 0 | varattno <= list_length(rcon->targetlist)) |
3051 | 0 | rcon->rv_cache[varattno] = copyObject(newnode); |
3052 | 0 | } |
3053 | 0 | } |
3054 | 0 | } |
3055 | | |
3056 | | /* Propagate any varnullingrels into the replacement expression */ |
3057 | 0 | if (var->varnullingrels != NULL) |
3058 | 0 | { |
3059 | 0 | if (IsA(newnode, Var)) |
3060 | 0 | { |
3061 | 0 | Var *newvar = (Var *) newnode; |
3062 | |
|
3063 | 0 | Assert(newvar->varlevelsup == 0); |
3064 | 0 | newvar->varnullingrels = bms_add_members(newvar->varnullingrels, |
3065 | 0 | var->varnullingrels); |
3066 | 0 | } |
3067 | 0 | else if (IsA(newnode, PlaceHolderVar)) |
3068 | 0 | { |
3069 | 0 | PlaceHolderVar *newphv = (PlaceHolderVar *) newnode; |
3070 | |
|
3071 | 0 | Assert(newphv->phlevelsup == 0); |
3072 | 0 | newphv->phnullingrels = bms_add_members(newphv->phnullingrels, |
3073 | 0 | var->varnullingrels); |
3074 | 0 | } |
3075 | 0 | else |
3076 | 0 | { |
3077 | | /* |
3078 | | * There should be Vars/PHVs within the expression that we can |
3079 | | * modify. Vars/PHVs of the subquery should have the full |
3080 | | * var->varnullingrels added to them, but if there are lateral |
3081 | | * references within the expression, those must be marked with |
3082 | | * only the nullingrels that potentially apply to them. (This |
3083 | | * corresponds to the fact that the expression will now be |
3084 | | * evaluated at the join level of the Var that we are replacing: |
3085 | | * the lateral references may have bubbled up through fewer outer |
3086 | | * joins than the subquery's Vars have. Per the discussion above, |
3087 | | * we'll still get the right answers.) That relid set could be |
3088 | | * different for different lateral relations, so we have to do |
3089 | | * this work for each one. |
3090 | | * |
3091 | | * (Currently, the restrictions in is_simple_subquery() mean that |
3092 | | * at most we have to remove the lowest outer join's relid from |
3093 | | * the nullingrels of a lateral reference. However, we might |
3094 | | * relax those restrictions someday, so let's do this right.) |
3095 | | */ |
3096 | 0 | if (rcon->target_rte->lateral) |
3097 | 0 | { |
3098 | 0 | nullingrel_info *nullinfo = rcon->nullinfo; |
3099 | 0 | Relids lvarnos; |
3100 | 0 | int lvarno; |
3101 | | |
3102 | | /* |
3103 | | * Identify lateral varnos used within newnode. We must do |
3104 | | * this before injecting var->varnullingrels into the tree. |
3105 | | */ |
3106 | 0 | lvarnos = pull_varnos(rcon->root, newnode); |
3107 | 0 | lvarnos = bms_del_members(lvarnos, rcon->relids); |
3108 | | /* For each one, add relevant nullingrels if any */ |
3109 | 0 | lvarno = -1; |
3110 | 0 | while ((lvarno = bms_next_member(lvarnos, lvarno)) >= 0) |
3111 | 0 | { |
3112 | 0 | Relids lnullingrels; |
3113 | |
|
3114 | 0 | Assert(lvarno > 0 && lvarno <= nullinfo->rtlength); |
3115 | 0 | lnullingrels = bms_intersect(var->varnullingrels, |
3116 | 0 | nullinfo->nullingrels[lvarno]); |
3117 | 0 | if (!bms_is_empty(lnullingrels)) |
3118 | 0 | newnode = add_nulling_relids(newnode, |
3119 | 0 | bms_make_singleton(lvarno), |
3120 | 0 | lnullingrels); |
3121 | 0 | } |
3122 | 0 | } |
3123 | | |
3124 | | /* Finally, deal with Vars/PHVs of the subquery itself */ |
3125 | 0 | newnode = add_nulling_relids(newnode, |
3126 | 0 | rcon->relids, |
3127 | 0 | var->varnullingrels); |
3128 | | /* Assert we did put the varnullingrels into the expression */ |
3129 | 0 | Assert(bms_is_subset(var->varnullingrels, |
3130 | 0 | pull_varnos(rcon->root, newnode))); |
3131 | 0 | } |
3132 | 0 | } |
3133 | | |
3134 | | /* Must adjust varlevelsup if replaced Var is within a subquery */ |
3135 | 0 | if (var->varlevelsup > 0) |
3136 | 0 | IncrementVarSublevelsUp(newnode, var->varlevelsup, 0); |
3137 | |
|
3138 | 0 | return newnode; |
3139 | 0 | } |
3140 | | |
3141 | | /* |
3142 | | * Apply pullup variable replacement to a subquery |
3143 | | * |
3144 | | * This needs to be different from pullup_replace_vars() because |
3145 | | * replace_rte_variables will think that it shouldn't increment sublevels_up |
3146 | | * before entering the Query; so we need to call it with sublevels_up == 1. |
3147 | | */ |
3148 | | static Query * |
3149 | | pullup_replace_vars_subquery(Query *query, |
3150 | | pullup_replace_vars_context *context) |
3151 | 0 | { |
3152 | 0 | Assert(IsA(query, Query)); |
3153 | 0 | return (Query *) replace_rte_variables((Node *) query, |
3154 | 0 | context->varno, 1, |
3155 | 0 | pullup_replace_vars_callback, |
3156 | 0 | context, |
3157 | 0 | NULL); |
3158 | 0 | } |
3159 | | |
3160 | | |
3161 | | /* |
3162 | | * flatten_simple_union_all |
3163 | | * Try to optimize top-level UNION ALL structure into an appendrel |
3164 | | * |
3165 | | * If a query's setOperations tree consists entirely of simple UNION ALL |
3166 | | * operations, flatten it into an append relation, which we can process more |
3167 | | * intelligently than the general setops case. Otherwise, do nothing. |
3168 | | * |
3169 | | * In most cases, this can succeed only for a top-level query, because for a |
3170 | | * subquery in FROM, the parent query's invocation of pull_up_subqueries would |
3171 | | * already have flattened the UNION via pull_up_simple_union_all. But there |
3172 | | * are a few cases we can support here but not in that code path, for example |
3173 | | * when the subquery also contains ORDER BY. |
3174 | | */ |
3175 | | void |
3176 | | flatten_simple_union_all(PlannerInfo *root) |
3177 | 0 | { |
3178 | 0 | Query *parse = root->parse; |
3179 | 0 | SetOperationStmt *topop; |
3180 | 0 | Node *leftmostjtnode; |
3181 | 0 | int leftmostRTI; |
3182 | 0 | RangeTblEntry *leftmostRTE; |
3183 | 0 | int childRTI; |
3184 | 0 | RangeTblEntry *childRTE; |
3185 | 0 | RangeTblRef *rtr; |
3186 | | |
3187 | | /* Shouldn't be called unless query has setops */ |
3188 | 0 | topop = castNode(SetOperationStmt, parse->setOperations); |
3189 | 0 | Assert(topop); |
3190 | | |
3191 | | /* Can't optimize away a recursive UNION */ |
3192 | 0 | if (root->hasRecursion) |
3193 | 0 | return; |
3194 | | |
3195 | | /* |
3196 | | * Recursively check the tree of set operations. If not all UNION ALL |
3197 | | * with identical column types, punt. |
3198 | | */ |
3199 | 0 | if (!is_simple_union_all_recurse((Node *) topop, parse, topop->colTypes)) |
3200 | 0 | return; |
3201 | | |
3202 | | /* |
3203 | | * Locate the leftmost leaf query in the setops tree. The upper query's |
3204 | | * Vars all refer to this RTE (see transformSetOperationStmt). |
3205 | | */ |
3206 | 0 | leftmostjtnode = topop->larg; |
3207 | 0 | while (leftmostjtnode && IsA(leftmostjtnode, SetOperationStmt)) |
3208 | 0 | leftmostjtnode = ((SetOperationStmt *) leftmostjtnode)->larg; |
3209 | 0 | Assert(leftmostjtnode && IsA(leftmostjtnode, RangeTblRef)); |
3210 | 0 | leftmostRTI = ((RangeTblRef *) leftmostjtnode)->rtindex; |
3211 | 0 | leftmostRTE = rt_fetch(leftmostRTI, parse->rtable); |
3212 | 0 | Assert(leftmostRTE->rtekind == RTE_SUBQUERY); |
3213 | | |
3214 | | /* |
3215 | | * Make a copy of the leftmost RTE and add it to the rtable. This copy |
3216 | | * will represent the leftmost leaf query in its capacity as a member of |
3217 | | * the appendrel. The original will represent the appendrel as a whole. |
3218 | | * (We must do things this way because the upper query's Vars have to be |
3219 | | * seen as referring to the whole appendrel.) |
3220 | | */ |
3221 | 0 | childRTE = copyObject(leftmostRTE); |
3222 | 0 | parse->rtable = lappend(parse->rtable, childRTE); |
3223 | 0 | childRTI = list_length(parse->rtable); |
3224 | | |
3225 | | /* Modify the setops tree to reference the child copy */ |
3226 | 0 | ((RangeTblRef *) leftmostjtnode)->rtindex = childRTI; |
3227 | | |
3228 | | /* Modify the formerly-leftmost RTE to mark it as an appendrel parent */ |
3229 | 0 | leftmostRTE->inh = true; |
3230 | | |
3231 | | /* |
3232 | | * Form a RangeTblRef for the appendrel, and insert it into FROM. The top |
3233 | | * Query of a setops tree should have had an empty FromClause initially. |
3234 | | */ |
3235 | 0 | rtr = makeNode(RangeTblRef); |
3236 | 0 | rtr->rtindex = leftmostRTI; |
3237 | 0 | Assert(parse->jointree->fromlist == NIL); |
3238 | 0 | parse->jointree->fromlist = list_make1(rtr); |
3239 | | |
3240 | | /* |
3241 | | * Now pretend the query has no setops. We must do this before trying to |
3242 | | * do subquery pullup, because of Assert in pull_up_simple_subquery. |
3243 | | */ |
3244 | 0 | parse->setOperations = NULL; |
3245 | | |
3246 | | /* |
3247 | | * Build AppendRelInfo information, and apply pull_up_subqueries to the |
3248 | | * leaf queries of the UNION ALL. (We must do that now because they |
3249 | | * weren't previously referenced by the jointree, and so were missed by |
3250 | | * the main invocation of pull_up_subqueries.) |
3251 | | */ |
3252 | 0 | pull_up_union_leaf_queries((Node *) topop, root, leftmostRTI, parse, 0); |
3253 | 0 | } |
3254 | | |
3255 | | |
3256 | | /* |
3257 | | * reduce_outer_joins |
3258 | | * Attempt to reduce outer joins to plain inner joins. |
3259 | | * |
3260 | | * The idea here is that given a query like |
3261 | | * SELECT ... FROM a LEFT JOIN b ON (...) WHERE b.y = 42; |
3262 | | * we can reduce the LEFT JOIN to a plain JOIN if the "=" operator in WHERE |
3263 | | * is strict. The strict operator will always return NULL, causing the outer |
3264 | | * WHERE to fail, on any row where the LEFT JOIN filled in NULLs for b's |
3265 | | * columns. Therefore, there's no need for the join to produce null-extended |
3266 | | * rows in the first place --- which makes it a plain join not an outer join. |
3267 | | * (This scenario may not be very likely in a query written out by hand, but |
3268 | | * it's reasonably likely when pushing quals down into complex views.) |
3269 | | * |
3270 | | * More generally, an outer join can be reduced in strength if there is a |
3271 | | * strict qual above it in the qual tree that constrains a Var from the |
3272 | | * nullable side of the join to be non-null. (For FULL joins this applies |
3273 | | * to each side separately.) |
3274 | | * |
3275 | | * Another transformation we apply here is to recognize cases like |
3276 | | * SELECT ... FROM a LEFT JOIN b ON (a.x = b.y) WHERE b.z IS NULL; |
3277 | | * If we can prove that b.z must be non-null for any matching row, because |
3278 | | * the join clause is strict for b.z and b.z happens to be the join key b.y, |
3279 | | * because a strict qual within b's own subtree forces b.z non-null, or |
3280 | | * because b.z is defined NOT NULL by table constraints and is not nullable |
3281 | | * due to lower-level outer joins, then only null-extended rows could pass |
3282 | | * the upper WHERE, and we can conclude that what the query is really |
3283 | | * specifying is an anti-semijoin. We change the join type from JOIN_LEFT |
3284 | | * to JOIN_ANTI. The IS NULL clause then becomes redundant, and is removed |
3285 | | * at the end of this phase; see remove_redundant_nullability_quals. |
3286 | | * |
3287 | | * A whole-row Var works too. "WHERE b IS NULL" in row-format semantics is |
3288 | | * true when b's whole-row value is NULL or when every column of b is NULL; |
3289 | | * for a matching row only the latter is possible, so proving any one column |
3290 | | * of b non-null in matching rows justifies the same reduction. |
3291 | | * |
3292 | | * The same recognition reduces a FULL join to an anti-semijoin when a |
3293 | | * forced-null Var on either side is proven non-null: only the other side's |
3294 | | * unmatched rows can survive. If that surviving side is the right-hand |
3295 | | * input, we switch the inputs (as we do for JOIN_RIGHT below) so that it |
3296 | | * ends up on the left, where JOIN_ANTI requires the surviving side to be. |
3297 | | * |
3298 | | * Also, we get rid of JOIN_RIGHT cases by flipping them around to become |
3299 | | * JOIN_LEFT. This saves some code here and in some later planner routines; |
3300 | | * the main benefit is to reduce the number of jointypes that can appear in |
3301 | | * SpecialJoinInfo nodes. Note that we can still generate Paths and Plans |
3302 | | * that use JOIN_RIGHT (or JOIN_RIGHT_ANTI) by switching the inputs again. |
3303 | | * |
3304 | | * To ease recognition of strict qual clauses, we require this routine to be |
3305 | | * run after expression preprocessing (i.e., qual canonicalization and JOIN |
3306 | | * alias-var expansion). |
3307 | | */ |
3308 | | void |
3309 | | reduce_outer_joins(PlannerInfo *root) |
3310 | 0 | { |
3311 | 0 | reduce_outer_joins_pass1_state *state1; |
3312 | 0 | reduce_outer_joins_pass2_state state2; |
3313 | 0 | ListCell *lc; |
3314 | | |
3315 | | /* |
3316 | | * To avoid doing strictness checks on more quals than necessary, we want |
3317 | | * to stop descending the jointree as soon as there are no outer joins |
3318 | | * below our current point. This consideration forces a two-pass process. |
3319 | | * The first pass gathers information about which base rels appear below |
3320 | | * each side of each join clause, about whether there are outer join(s) |
3321 | | * below each side of each join clause, and about which base rels are from |
3322 | | * the nullable side of those outer join(s). The second pass examines |
3323 | | * qual clauses and changes join types as it descends the tree. |
3324 | | */ |
3325 | 0 | state1 = reduce_outer_joins_pass1((Node *) root->parse->jointree); |
3326 | | |
3327 | | /* planner.c shouldn't have called me if no outer joins */ |
3328 | 0 | if (state1 == NULL || !state1->contains_outer) |
3329 | 0 | elog(ERROR, "so where are the outer joins?"); |
3330 | | |
3331 | 0 | state2.inner_reduced = NULL; |
3332 | 0 | state2.partial_reduced = NIL; |
3333 | 0 | state2.anti_reduced = NULL; |
3334 | |
|
3335 | 0 | reduce_outer_joins_pass2((Node *) root->parse->jointree, |
3336 | 0 | state1, &state2, |
3337 | 0 | root, NULL, NIL); |
3338 | | |
3339 | | /* |
3340 | | * If we successfully reduced the strength of any outer joins, we must |
3341 | | * remove references to those joins as nulling rels. This is handled as |
3342 | | * an additional pass, for simplicity and because we can handle all |
3343 | | * fully-reduced joins in a single pass over the parse tree. |
3344 | | */ |
3345 | 0 | if (!bms_is_empty(state2.inner_reduced)) |
3346 | 0 | { |
3347 | 0 | root->parse = (Query *) |
3348 | 0 | remove_nulling_relids((Node *) root->parse, |
3349 | 0 | state2.inner_reduced, |
3350 | 0 | NULL); |
3351 | | /* There could be references in the append_rel_list, too */ |
3352 | 0 | root->append_rel_list = (List *) |
3353 | 0 | remove_nulling_relids((Node *) root->append_rel_list, |
3354 | 0 | state2.inner_reduced, |
3355 | 0 | NULL); |
3356 | 0 | } |
3357 | | |
3358 | | /* |
3359 | | * Partially-reduced full joins have to be done one at a time, since |
3360 | | * they'll each need a different setting of except_relids. |
3361 | | */ |
3362 | 0 | foreach(lc, state2.partial_reduced) |
3363 | 0 | { |
3364 | 0 | reduce_outer_joins_partial_state *statep = lfirst(lc); |
3365 | 0 | Relids full_join_relids = bms_make_singleton(statep->full_join_rti); |
3366 | |
|
3367 | 0 | root->parse = (Query *) |
3368 | 0 | remove_nulling_relids((Node *) root->parse, |
3369 | 0 | full_join_relids, |
3370 | 0 | statep->unreduced_side); |
3371 | 0 | root->append_rel_list = (List *) |
3372 | 0 | remove_nulling_relids((Node *) root->append_rel_list, |
3373 | 0 | full_join_relids, |
3374 | 0 | statep->unreduced_side); |
3375 | 0 | } |
3376 | | |
3377 | | /* |
3378 | | * Finally, remove any quals made redundant by reducing outer joins to |
3379 | | * antijoins. |
3380 | | */ |
3381 | 0 | if (!bms_is_empty(state2.anti_reduced)) |
3382 | 0 | remove_redundant_nullability_quals((Node *) root->parse->jointree, |
3383 | 0 | state2.anti_reduced); |
3384 | 0 | } |
3385 | | |
3386 | | /* |
3387 | | * remove_redundant_nullability_quals |
3388 | | * Remove quals made redundant by reducing outer joins to antijoins. |
3389 | | * |
3390 | | * An IS NULL qual on a Var from the nullable side of a lower antijoin is |
3391 | | * necessarily true. Keeping such a qual would not be wrong, but it would |
3392 | | * generate bogus selectivity estimates, and it could prevent join removal |
3393 | | * from later removing the rel(s) it references. |
3394 | | */ |
3395 | | static void |
3396 | | remove_redundant_nullability_quals(Node *jtnode, Relids antijoins) |
3397 | 0 | { |
3398 | 0 | if (jtnode == NULL) |
3399 | 0 | return; |
3400 | 0 | if (IsA(jtnode, RangeTblRef)) |
3401 | 0 | { |
3402 | | /* nothing to do here */ |
3403 | 0 | } |
3404 | 0 | else if (IsA(jtnode, FromExpr)) |
3405 | 0 | { |
3406 | 0 | FromExpr *f = (FromExpr *) jtnode; |
3407 | 0 | ListCell *l; |
3408 | |
|
3409 | 0 | foreach(l, f->fromlist) |
3410 | 0 | remove_redundant_nullability_quals(lfirst(l), antijoins); |
3411 | 0 | f->quals = strip_redundant_nullability_quals(f->quals, antijoins); |
3412 | 0 | } |
3413 | 0 | else if (IsA(jtnode, JoinExpr)) |
3414 | 0 | { |
3415 | 0 | JoinExpr *j = (JoinExpr *) jtnode; |
3416 | |
|
3417 | 0 | remove_redundant_nullability_quals(j->larg, antijoins); |
3418 | 0 | remove_redundant_nullability_quals(j->rarg, antijoins); |
3419 | 0 | j->quals = strip_redundant_nullability_quals(j->quals, antijoins); |
3420 | 0 | } |
3421 | 0 | else |
3422 | 0 | elog(ERROR, "unrecognized jointree node type: %d", |
3423 | 0 | (int) nodeTag(jtnode)); |
3424 | 0 | } |
3425 | | |
3426 | | /* |
3427 | | * strip_redundant_nullability_quals |
3428 | | * Strip redundant IS NULL quals from one implicit-AND qual list. |
3429 | | */ |
3430 | | static Node * |
3431 | | strip_redundant_nullability_quals(Node *quals, Relids antijoins) |
3432 | 0 | { |
3433 | 0 | List *newquals = NIL; |
3434 | |
|
3435 | 0 | foreach_ptr(Node, clause, castNode(List, quals)) |
3436 | 0 | { |
3437 | 0 | Var *var = find_forced_null_var(clause); |
3438 | |
|
3439 | 0 | if (var && bms_overlap(var->varnullingrels, antijoins)) |
3440 | 0 | continue; |
3441 | 0 | newquals = lappend(newquals, clause); |
3442 | 0 | } |
3443 | 0 | return (Node *) newquals; |
3444 | 0 | } |
3445 | | |
3446 | | /* |
3447 | | * reduce_outer_joins_pass1 - phase 1 data collection |
3448 | | * |
3449 | | * Returns a state node describing the given jointree node. |
3450 | | */ |
3451 | | static reduce_outer_joins_pass1_state * |
3452 | | reduce_outer_joins_pass1(Node *jtnode) |
3453 | 0 | { |
3454 | 0 | reduce_outer_joins_pass1_state *result; |
3455 | |
|
3456 | 0 | result = palloc_object(reduce_outer_joins_pass1_state); |
3457 | 0 | result->relids = NULL; |
3458 | 0 | result->contains_outer = false; |
3459 | 0 | result->nullable_rels = NULL; |
3460 | 0 | result->jtnode = jtnode; |
3461 | 0 | result->sub_states = NIL; |
3462 | |
|
3463 | 0 | if (jtnode == NULL) |
3464 | 0 | return result; |
3465 | 0 | if (IsA(jtnode, RangeTblRef)) |
3466 | 0 | { |
3467 | 0 | int varno = ((RangeTblRef *) jtnode)->rtindex; |
3468 | |
|
3469 | 0 | result->relids = bms_make_singleton(varno); |
3470 | 0 | } |
3471 | 0 | else if (IsA(jtnode, FromExpr)) |
3472 | 0 | { |
3473 | 0 | FromExpr *f = (FromExpr *) jtnode; |
3474 | 0 | ListCell *l; |
3475 | |
|
3476 | 0 | foreach(l, f->fromlist) |
3477 | 0 | { |
3478 | 0 | reduce_outer_joins_pass1_state *sub_state; |
3479 | |
|
3480 | 0 | sub_state = reduce_outer_joins_pass1(lfirst(l)); |
3481 | 0 | result->relids = bms_add_members(result->relids, |
3482 | 0 | sub_state->relids); |
3483 | 0 | result->contains_outer |= sub_state->contains_outer; |
3484 | 0 | result->nullable_rels = bms_add_members(result->nullable_rels, |
3485 | 0 | sub_state->nullable_rels); |
3486 | 0 | result->sub_states = lappend(result->sub_states, sub_state); |
3487 | 0 | } |
3488 | 0 | } |
3489 | 0 | else if (IsA(jtnode, JoinExpr)) |
3490 | 0 | { |
3491 | 0 | JoinExpr *j = (JoinExpr *) jtnode; |
3492 | 0 | reduce_outer_joins_pass1_state *left_state; |
3493 | 0 | reduce_outer_joins_pass1_state *right_state; |
3494 | | |
3495 | | /* Recurse to children */ |
3496 | 0 | left_state = reduce_outer_joins_pass1(j->larg); |
3497 | 0 | right_state = reduce_outer_joins_pass1(j->rarg); |
3498 | | |
3499 | | /* join's own RT index is not wanted in result->relids */ |
3500 | 0 | result->relids = bms_union(left_state->relids, right_state->relids); |
3501 | | |
3502 | | /* Store children's states for pass 2 */ |
3503 | 0 | result->sub_states = list_make2(left_state, right_state); |
3504 | | |
3505 | | /* Collect outer join information */ |
3506 | 0 | switch (j->jointype) |
3507 | 0 | { |
3508 | 0 | case JOIN_INNER: |
3509 | 0 | case JOIN_SEMI: |
3510 | | /* No new nullability; propagate state from children */ |
3511 | 0 | result->contains_outer = left_state->contains_outer || |
3512 | 0 | right_state->contains_outer; |
3513 | 0 | result->nullable_rels = bms_union(left_state->nullable_rels, |
3514 | 0 | right_state->nullable_rels); |
3515 | 0 | break; |
3516 | 0 | case JOIN_LEFT: |
3517 | 0 | case JOIN_ANTI: |
3518 | | /* RHS is nullable; LHS keeps existing status */ |
3519 | 0 | result->contains_outer = true; |
3520 | 0 | result->nullable_rels = bms_union(left_state->nullable_rels, |
3521 | 0 | right_state->relids); |
3522 | 0 | break; |
3523 | 0 | case JOIN_RIGHT: |
3524 | | /* LHS is nullable; RHS keeps existing status */ |
3525 | 0 | result->contains_outer = true; |
3526 | 0 | result->nullable_rels = bms_union(left_state->relids, |
3527 | 0 | right_state->nullable_rels); |
3528 | 0 | break; |
3529 | 0 | case JOIN_FULL: |
3530 | | /* Both sides are nullable */ |
3531 | 0 | result->contains_outer = true; |
3532 | 0 | result->nullable_rels = bms_union(left_state->relids, |
3533 | 0 | right_state->relids); |
3534 | 0 | break; |
3535 | 0 | default: |
3536 | 0 | elog(ERROR, "unrecognized join type: %d", |
3537 | 0 | (int) j->jointype); |
3538 | 0 | break; |
3539 | 0 | } |
3540 | 0 | } |
3541 | 0 | else |
3542 | 0 | elog(ERROR, "unrecognized node type: %d", |
3543 | 0 | (int) nodeTag(jtnode)); |
3544 | 0 | return result; |
3545 | 0 | } |
3546 | | |
3547 | | /* |
3548 | | * reduce_outer_joins_pass2 - phase 2 processing |
3549 | | * |
3550 | | * jtnode: current jointree node |
3551 | | * state1: state data collected by phase 1 for this node |
3552 | | * state2: where to accumulate info about successfully-reduced joins |
3553 | | * root: toplevel planner state |
3554 | | * nonnullable_rels: set of base relids forced non-null by upper quals |
3555 | | * forced_null_vars: multibitmapset of Vars forced null by upper quals |
3556 | | * |
3557 | | * Returns info in state2 about outer joins that were successfully simplified. |
3558 | | * Joins that were fully reduced to inner joins are all added to |
3559 | | * state2->inner_reduced, and joins that became antijoins are all added to |
3560 | | * state2->anti_reduced. If a full join is reduced to a left join or an |
3561 | | * antijoin, it also needs its own entry in state2->partial_reduced, since |
3562 | | * that will require custom processing to remove only the correct nullingrel |
3563 | | * markers. |
3564 | | */ |
3565 | | static void |
3566 | | reduce_outer_joins_pass2(Node *jtnode, |
3567 | | reduce_outer_joins_pass1_state *state1, |
3568 | | reduce_outer_joins_pass2_state *state2, |
3569 | | PlannerInfo *root, |
3570 | | Relids nonnullable_rels, |
3571 | | List *forced_null_vars) |
3572 | 0 | { |
3573 | | /* |
3574 | | * pass 2 should never descend as far as an empty subnode or base rel, |
3575 | | * because it's only called on subtrees marked as contains_outer. |
3576 | | */ |
3577 | 0 | if (jtnode == NULL) |
3578 | 0 | elog(ERROR, "reached empty jointree"); |
3579 | 0 | if (IsA(jtnode, RangeTblRef)) |
3580 | 0 | elog(ERROR, "reached base rel"); |
3581 | 0 | else if (IsA(jtnode, FromExpr)) |
3582 | 0 | { |
3583 | 0 | FromExpr *f = (FromExpr *) jtnode; |
3584 | 0 | ListCell *l; |
3585 | 0 | ListCell *s; |
3586 | 0 | Relids pass_nonnullable_rels; |
3587 | 0 | List *pass_forced_null_vars; |
3588 | | |
3589 | | /* Scan quals to see if we can add any constraints */ |
3590 | 0 | pass_nonnullable_rels = find_nonnullable_rels(f->quals); |
3591 | 0 | pass_nonnullable_rels = bms_add_members(pass_nonnullable_rels, |
3592 | 0 | nonnullable_rels); |
3593 | 0 | pass_forced_null_vars = find_forced_null_vars(f->quals); |
3594 | 0 | pass_forced_null_vars = mbms_add_members(pass_forced_null_vars, |
3595 | 0 | forced_null_vars); |
3596 | | /* And recurse --- but only into interesting subtrees */ |
3597 | 0 | Assert(list_length(f->fromlist) == list_length(state1->sub_states)); |
3598 | 0 | forboth(l, f->fromlist, s, state1->sub_states) |
3599 | 0 | { |
3600 | 0 | reduce_outer_joins_pass1_state *sub_state = lfirst(s); |
3601 | |
|
3602 | 0 | if (sub_state->contains_outer) |
3603 | 0 | reduce_outer_joins_pass2(lfirst(l), sub_state, |
3604 | 0 | state2, root, |
3605 | 0 | pass_nonnullable_rels, |
3606 | 0 | pass_forced_null_vars); |
3607 | 0 | } |
3608 | 0 | bms_free(pass_nonnullable_rels); |
3609 | | /* can't so easily clean up var lists, unfortunately */ |
3610 | 0 | } |
3611 | 0 | else if (IsA(jtnode, JoinExpr)) |
3612 | 0 | { |
3613 | 0 | JoinExpr *j = (JoinExpr *) jtnode; |
3614 | 0 | int rtindex = j->rtindex; |
3615 | 0 | JoinType jointype = j->jointype; |
3616 | 0 | reduce_outer_joins_pass1_state *left_state = linitial(state1->sub_states); |
3617 | 0 | reduce_outer_joins_pass1_state *right_state = lsecond(state1->sub_states); |
3618 | | |
3619 | | /* Can we simplify this join? */ |
3620 | 0 | switch (jointype) |
3621 | 0 | { |
3622 | 0 | case JOIN_INNER: |
3623 | 0 | break; |
3624 | 0 | case JOIN_LEFT: |
3625 | 0 | if (bms_overlap(nonnullable_rels, right_state->relids)) |
3626 | 0 | jointype = JOIN_INNER; |
3627 | 0 | break; |
3628 | 0 | case JOIN_RIGHT: |
3629 | 0 | if (bms_overlap(nonnullable_rels, left_state->relids)) |
3630 | 0 | jointype = JOIN_INNER; |
3631 | 0 | break; |
3632 | 0 | case JOIN_FULL: |
3633 | 0 | if (bms_overlap(nonnullable_rels, left_state->relids)) |
3634 | 0 | { |
3635 | 0 | if (bms_overlap(nonnullable_rels, right_state->relids)) |
3636 | 0 | jointype = JOIN_INNER; |
3637 | 0 | else |
3638 | 0 | { |
3639 | 0 | jointype = JOIN_LEFT; |
3640 | | /* Also report partial reduction in state2 */ |
3641 | 0 | report_reduced_full_join(state2, rtindex, |
3642 | 0 | right_state->relids); |
3643 | 0 | } |
3644 | 0 | } |
3645 | 0 | else if (bms_overlap(nonnullable_rels, right_state->relids)) |
3646 | 0 | { |
3647 | 0 | jointype = JOIN_RIGHT; |
3648 | | /* Also report partial reduction in state2 */ |
3649 | 0 | report_reduced_full_join(state2, rtindex, |
3650 | 0 | left_state->relids); |
3651 | 0 | } |
3652 | 0 | else if (forced_null_vars != NIL) |
3653 | 0 | { |
3654 | | /* |
3655 | | * Neither side is forced non-null by a strict upper qual, |
3656 | | * but an upper qual may force a Var on one side to be |
3657 | | * NULL while that Var is non-null in every row that side |
3658 | | * emits (proven by quals within the side's own subtree, |
3659 | | * or a NOT NULL constraint). Then only rows where that |
3660 | | * side was null-extended can satisfy the upper qual: the |
3661 | | * matched rows and that side's unmatched rows all drop |
3662 | | * out, leaving an anti-join. |
3663 | | * |
3664 | | * Unlike the JOIN_LEFT case below, we must not consult |
3665 | | * the join's own ON quals here: they do not hold for the |
3666 | | * unmatched rows that this proof has to cover. |
3667 | | * |
3668 | | * If the constrained Var is on the RHS the result is a |
3669 | | * plain anti-join; if it is on the LHS it is a right |
3670 | | * anti-join, which the input-switching step below |
3671 | | * normalizes to a plain anti-join (just as it does for |
3672 | | * JOIN_RIGHT). |
3673 | | */ |
3674 | 0 | if (forced_null_var_is_nonnullable(root, |
3675 | 0 | forced_null_vars, |
3676 | 0 | right_state, NIL)) |
3677 | 0 | { |
3678 | 0 | jointype = JOIN_ANTI; |
3679 | 0 | report_reduced_full_join(state2, rtindex, |
3680 | 0 | right_state->relids); |
3681 | 0 | } |
3682 | 0 | else if (forced_null_var_is_nonnullable(root, |
3683 | 0 | forced_null_vars, |
3684 | 0 | left_state, NIL)) |
3685 | 0 | { |
3686 | 0 | jointype = JOIN_RIGHT_ANTI; |
3687 | 0 | report_reduced_full_join(state2, rtindex, |
3688 | 0 | left_state->relids); |
3689 | 0 | } |
3690 | 0 | } |
3691 | 0 | break; |
3692 | 0 | case JOIN_SEMI: |
3693 | 0 | case JOIN_ANTI: |
3694 | | |
3695 | | /* |
3696 | | * These could only have been introduced by pull_up_sublinks, |
3697 | | * so there's no way that upper quals could refer to their |
3698 | | * righthand sides, and no point in checking. We don't expect |
3699 | | * a JOIN_RIGHT_SEMI or JOIN_RIGHT_ANTI input here; the |
3700 | | * JOIN_FULL case above produces JOIN_RIGHT_ANTI only as a |
3701 | | * transient, which is converted to JOIN_ANTI below. |
3702 | | */ |
3703 | 0 | break; |
3704 | 0 | default: |
3705 | 0 | elog(ERROR, "unrecognized join type: %d", |
3706 | 0 | (int) jointype); |
3707 | 0 | break; |
3708 | 0 | } |
3709 | | |
3710 | | /* |
3711 | | * Convert JOIN_RIGHT to JOIN_LEFT, and likewise the JOIN_RIGHT_ANTI |
3712 | | * that the JOIN_FULL arm may have produced just above to JOIN_ANTI, |
3713 | | * by switching the inputs. Note that in the case where we reduced |
3714 | | * JOIN_FULL this way, this will mean the JoinExpr no longer matches |
3715 | | * the internal ordering of any CoalesceExpr's built to represent |
3716 | | * merged join variables. We don't care about that at present, but be |
3717 | | * wary of it ... |
3718 | | */ |
3719 | 0 | if (jointype == JOIN_RIGHT || jointype == JOIN_RIGHT_ANTI) |
3720 | 0 | { |
3721 | 0 | Node *tmparg; |
3722 | |
|
3723 | 0 | tmparg = j->larg; |
3724 | 0 | j->larg = j->rarg; |
3725 | 0 | j->rarg = tmparg; |
3726 | 0 | jointype = (jointype == JOIN_RIGHT) ? JOIN_LEFT : JOIN_ANTI; |
3727 | 0 | right_state = linitial(state1->sub_states); |
3728 | 0 | left_state = lsecond(state1->sub_states); |
3729 | 0 | } |
3730 | | |
3731 | | /* |
3732 | | * See if we can reduce JOIN_LEFT to JOIN_ANTI. This is the case if |
3733 | | * any var from the RHS was forced null by higher qual levels, but is |
3734 | | * known to be non-nullable in any matching row. We can prove that in |
3735 | | * any of these ways: the join's own quals are strict for the var; |
3736 | | * strict quals applied within the RHS subtree prove it; or the var is |
3737 | | * defined NOT NULL by table constraints (being careful to exclude |
3738 | | * vars that are nullable due to lower-level outer joins). In each |
3739 | | * such case, the only way the higher qual clause's requirement for |
3740 | | * NULL can be met is if the join fails to match, producing a |
3741 | | * null-extended row. Thus, we can treat this as an anti-join. |
3742 | | */ |
3743 | 0 | if (jointype == JOIN_LEFT && forced_null_vars != NIL) |
3744 | 0 | { |
3745 | | /* |
3746 | | * A forced-null RHS Var that is proven non-null can be NULL here |
3747 | | * only by null-extension. That makes this an anti-join. |
3748 | | */ |
3749 | 0 | if (forced_null_var_is_nonnullable(root, forced_null_vars, |
3750 | 0 | right_state, (List *) j->quals)) |
3751 | 0 | jointype = JOIN_ANTI; |
3752 | 0 | } |
3753 | | |
3754 | | /* |
3755 | | * Apply the jointype change, if any, to both jointree node and RTE. |
3756 | | * Also, if we changed an RTE to INNER, add its RTI to inner_reduced; |
3757 | | * if we changed it to ANTI, add its RTI to anti_reduced. |
3758 | | */ |
3759 | 0 | if (rtindex && jointype != j->jointype) |
3760 | 0 | { |
3761 | 0 | RangeTblEntry *rte = rt_fetch(rtindex, root->parse->rtable); |
3762 | |
|
3763 | 0 | Assert(rte->rtekind == RTE_JOIN); |
3764 | 0 | Assert(rte->jointype == j->jointype); |
3765 | 0 | rte->jointype = jointype; |
3766 | 0 | if (jointype == JOIN_INNER) |
3767 | 0 | state2->inner_reduced = bms_add_member(state2->inner_reduced, |
3768 | 0 | rtindex); |
3769 | 0 | else if (jointype == JOIN_ANTI) |
3770 | 0 | state2->anti_reduced = bms_add_member(state2->anti_reduced, |
3771 | 0 | rtindex); |
3772 | 0 | } |
3773 | 0 | j->jointype = jointype; |
3774 | | |
3775 | | /* Only recurse if there's more to do below here */ |
3776 | 0 | if (left_state->contains_outer || right_state->contains_outer) |
3777 | 0 | { |
3778 | 0 | Relids local_nonnullable_rels; |
3779 | 0 | List *local_forced_null_vars; |
3780 | 0 | Relids pass_nonnullable_rels; |
3781 | 0 | List *pass_forced_null_vars; |
3782 | | |
3783 | | /* |
3784 | | * If this join is (now) inner, we can add any constraints its |
3785 | | * quals provide to those we got from above. But if it is outer, |
3786 | | * we can pass down the local constraints only into the nullable |
3787 | | * side, because an outer join never eliminates any rows from its |
3788 | | * non-nullable side. Also, there is no point in passing upper |
3789 | | * constraints into the nullable side, since if there were any |
3790 | | * we'd have been able to reduce the join. (In the case of upper |
3791 | | * forced-null constraints, we *must not* pass them into the |
3792 | | * nullable side --- they either applied here, or not.) The upshot |
3793 | | * is that we pass either the local or the upper constraints, |
3794 | | * never both, to the children of an outer join. |
3795 | | * |
3796 | | * Note that a SEMI join works like an inner join here: it's okay |
3797 | | * to pass down both local and upper constraints. (There can't be |
3798 | | * any upper constraints affecting its inner side, but it's not |
3799 | | * worth having a separate code path to avoid passing them.) |
3800 | | * |
3801 | | * At a FULL join we just punt and pass nothing down --- is it |
3802 | | * possible to be smarter? |
3803 | | */ |
3804 | 0 | if (jointype != JOIN_FULL) |
3805 | 0 | { |
3806 | 0 | local_nonnullable_rels = find_nonnullable_rels(j->quals); |
3807 | 0 | local_forced_null_vars = find_forced_null_vars(j->quals); |
3808 | 0 | if (jointype == JOIN_INNER || jointype == JOIN_SEMI) |
3809 | 0 | { |
3810 | | /* OK to merge upper and local constraints */ |
3811 | 0 | local_nonnullable_rels = bms_add_members(local_nonnullable_rels, |
3812 | 0 | nonnullable_rels); |
3813 | 0 | local_forced_null_vars = mbms_add_members(local_forced_null_vars, |
3814 | 0 | forced_null_vars); |
3815 | 0 | } |
3816 | 0 | } |
3817 | 0 | else |
3818 | 0 | { |
3819 | | /* no use in calculating these */ |
3820 | 0 | local_nonnullable_rels = NULL; |
3821 | 0 | local_forced_null_vars = NIL; |
3822 | 0 | } |
3823 | |
|
3824 | 0 | if (left_state->contains_outer) |
3825 | 0 | { |
3826 | 0 | if (jointype == JOIN_INNER || jointype == JOIN_SEMI) |
3827 | 0 | { |
3828 | | /* pass union of local and upper constraints */ |
3829 | 0 | pass_nonnullable_rels = local_nonnullable_rels; |
3830 | 0 | pass_forced_null_vars = local_forced_null_vars; |
3831 | 0 | } |
3832 | 0 | else if (jointype != JOIN_FULL) /* ie, LEFT or ANTI */ |
3833 | 0 | { |
3834 | | /* can't pass local constraints to non-nullable side */ |
3835 | 0 | pass_nonnullable_rels = nonnullable_rels; |
3836 | 0 | pass_forced_null_vars = forced_null_vars; |
3837 | 0 | } |
3838 | 0 | else |
3839 | 0 | { |
3840 | | /* no constraints pass through JOIN_FULL */ |
3841 | 0 | pass_nonnullable_rels = NULL; |
3842 | 0 | pass_forced_null_vars = NIL; |
3843 | 0 | } |
3844 | 0 | reduce_outer_joins_pass2(j->larg, left_state, |
3845 | 0 | state2, root, |
3846 | 0 | pass_nonnullable_rels, |
3847 | 0 | pass_forced_null_vars); |
3848 | 0 | } |
3849 | |
|
3850 | 0 | if (right_state->contains_outer) |
3851 | 0 | { |
3852 | 0 | if (jointype != JOIN_FULL) /* ie, INNER/LEFT/SEMI/ANTI */ |
3853 | 0 | { |
3854 | | /* pass appropriate constraints, per comment above */ |
3855 | 0 | pass_nonnullable_rels = local_nonnullable_rels; |
3856 | 0 | pass_forced_null_vars = local_forced_null_vars; |
3857 | 0 | } |
3858 | 0 | else |
3859 | 0 | { |
3860 | | /* no constraints pass through JOIN_FULL */ |
3861 | 0 | pass_nonnullable_rels = NULL; |
3862 | 0 | pass_forced_null_vars = NIL; |
3863 | 0 | } |
3864 | 0 | reduce_outer_joins_pass2(j->rarg, right_state, |
3865 | 0 | state2, root, |
3866 | 0 | pass_nonnullable_rels, |
3867 | 0 | pass_forced_null_vars); |
3868 | 0 | } |
3869 | 0 | bms_free(local_nonnullable_rels); |
3870 | 0 | } |
3871 | 0 | } |
3872 | 0 | else |
3873 | 0 | elog(ERROR, "unrecognized node type: %d", |
3874 | 0 | (int) nodeTag(jtnode)); |
3875 | 0 | } |
3876 | | |
3877 | | /* Helper for reduce_outer_joins_pass2 */ |
3878 | | static void |
3879 | | report_reduced_full_join(reduce_outer_joins_pass2_state *state2, |
3880 | | int rtindex, Relids relids) |
3881 | 0 | { |
3882 | 0 | reduce_outer_joins_partial_state *statep; |
3883 | |
|
3884 | 0 | statep = palloc_object(reduce_outer_joins_partial_state); |
3885 | 0 | statep->full_join_rti = rtindex; |
3886 | 0 | statep->unreduced_side = relids; |
3887 | 0 | state2->partial_reduced = lappend(state2->partial_reduced, statep); |
3888 | 0 | } |
3889 | | |
3890 | | /* |
3891 | | * forced_null_var_is_attnotnull |
3892 | | * Check if "forced_null_vars" contains any Vars belonging to the subtree |
3893 | | * indicated by "state" that are known to be non-nullable due to table |
3894 | | * constraints. |
3895 | | * |
3896 | | * A whole-row Var, in any matching row, requires every column of its relation |
3897 | | * to be NULL, so any NOT NULL column of the relation refutes it. |
3898 | | * |
3899 | | * Note that we must also consider the situation where a NOT NULL Var can be |
3900 | | * nulled by lower-level outer joins. |
3901 | | * |
3902 | | * Helper for reduce_outer_joins_pass2. |
3903 | | */ |
3904 | | static bool |
3905 | | forced_null_var_is_attnotnull(PlannerInfo *root, List *forced_null_vars, |
3906 | | reduce_outer_joins_pass1_state *state) |
3907 | 0 | { |
3908 | 0 | int varno = -1; |
3909 | |
|
3910 | 0 | foreach_node(Bitmapset, attrs, forced_null_vars) |
3911 | 0 | { |
3912 | 0 | RangeTblEntry *rte; |
3913 | 0 | Bitmapset *notnullattnums; |
3914 | 0 | Bitmapset *forcednullattnums; |
3915 | 0 | bool wholerow = false; |
3916 | 0 | int lowest_attno; |
3917 | |
|
3918 | 0 | varno++; |
3919 | | |
3920 | | /* Skip empty bitmaps */ |
3921 | 0 | if (bms_is_empty(attrs)) |
3922 | 0 | continue; |
3923 | | |
3924 | | /* Skip Vars that do not belong to the target relations */ |
3925 | 0 | if (!bms_is_member(varno, state->relids)) |
3926 | 0 | continue; |
3927 | | |
3928 | | /* |
3929 | | * Skip Vars that can be nulled by lower-level outer joins within the |
3930 | | * given subtree. These Vars might be NULL even if the schema defines |
3931 | | * them as NOT NULL. |
3932 | | */ |
3933 | 0 | if (bms_is_member(varno, state->nullable_rels)) |
3934 | 0 | continue; |
3935 | | |
3936 | | /* find the lowest member to check if system columns are present */ |
3937 | 0 | lowest_attno = bms_next_member(attrs, -1); |
3938 | | |
3939 | | /* we checked for an empty set above */ |
3940 | 0 | Assert(lowest_attno >= 0); |
3941 | | |
3942 | | /* system columns cannot be NULL */ |
3943 | 0 | if (lowest_attno + FirstLowInvalidHeapAttributeNumber < 0) |
3944 | 0 | return true; |
3945 | | |
3946 | | /* attno 0 is a whole-row Var, which forces every column null */ |
3947 | 0 | if (lowest_attno + FirstLowInvalidHeapAttributeNumber == 0) |
3948 | 0 | wholerow = true; |
3949 | |
|
3950 | 0 | rte = rt_fetch(varno, root->parse->rtable); |
3951 | | |
3952 | | /* We can only reason about ordinary relations */ |
3953 | 0 | if (rte->rtekind != RTE_RELATION) |
3954 | 0 | continue; |
3955 | | |
3956 | | /* |
3957 | | * We must skip inheritance parent tables, as some child tables may |
3958 | | * have a NOT NULL constraint for a column while others may not. This |
3959 | | * cannot happen with partitioned tables, though. |
3960 | | */ |
3961 | 0 | if (rte->inh && rte->relkind != RELKIND_PARTITIONED_TABLE) |
3962 | 0 | continue; |
3963 | | |
3964 | | /* Get the column not-null constraint information for this relation */ |
3965 | 0 | notnullattnums = find_relation_notnullatts(root, rte->relid); |
3966 | | |
3967 | | /* |
3968 | | * A forced-null whole-row Var, in any matching row, requires every |
3969 | | * column of the relation to be NULL, so any NOT NULL column refutes |
3970 | | * it. |
3971 | | */ |
3972 | 0 | if (wholerow && !bms_is_empty(notnullattnums)) |
3973 | 0 | return true; |
3974 | | |
3975 | | /* |
3976 | | * Offset the bitmap members by FirstLowInvalidHeapAttributeNumber to |
3977 | | * get the actual attribute numbers. |
3978 | | */ |
3979 | 0 | forcednullattnums = bms_offset_members(attrs, |
3980 | 0 | FirstLowInvalidHeapAttributeNumber); |
3981 | | |
3982 | | /* |
3983 | | * Check if any forced-null attributes are defined as NOT NULL by |
3984 | | * table constraints. |
3985 | | */ |
3986 | 0 | if (bms_overlap(notnullattnums, forcednullattnums)) |
3987 | 0 | { |
3988 | 0 | bms_free(forcednullattnums); |
3989 | 0 | return true; |
3990 | 0 | } |
3991 | | |
3992 | 0 | bms_free(forcednullattnums); |
3993 | 0 | } |
3994 | | |
3995 | 0 | return false; |
3996 | 0 | } |
3997 | | |
3998 | | /* |
3999 | | * forced_null_var_is_nonnullable |
4000 | | * Detect whether some Var that "forced_null_vars" requires to be NULL is |
4001 | | * actually non-nullable in every row that the given subtree emits. |
4002 | | * |
4003 | | * We prove non-nullness from quals that hold for every such row: the subtree's |
4004 | | * safe quals, plus any "extra_quals" the caller knows also constrain the Var, |
4005 | | * or a NOT NULL table constraint (excluding Vars nullable due to lower-level |
4006 | | * outer joins). |
4007 | | * |
4008 | | * A whole-row Var in "forced_null_vars" requires, in any matching row, every |
4009 | | * column of its relation to be NULL, so it is refuted by proving any one of |
4010 | | * those columns non-null. |
4011 | | * |
4012 | | * Helper for reduce_outer_joins_pass2. |
4013 | | */ |
4014 | | static bool |
4015 | | forced_null_var_is_nonnullable(PlannerInfo *root, List *forced_null_vars, |
4016 | | reduce_outer_joins_pass1_state *state, |
4017 | | List *extra_quals) |
4018 | 0 | { |
4019 | 0 | List *all_quals = NIL; |
4020 | 0 | List *nonnullable_vars; |
4021 | 0 | int wholerow_attno = 0 - FirstLowInvalidHeapAttributeNumber; |
4022 | 0 | int varno = -1; |
4023 | |
|
4024 | 0 | find_safe_quals(state->jtnode, &all_quals); |
4025 | 0 | all_quals = list_concat(all_quals, extra_quals); |
4026 | 0 | nonnullable_vars = find_nonnullable_vars((Node *) all_quals); |
4027 | | |
4028 | | /* |
4029 | | * It's not sufficient to consider all matches between nonnullable_vars |
4030 | | * and forced_null_vars: a match counts only for a Var belonging to this |
4031 | | * subtree, and the whole-row attribute needs special treatment. |
4032 | | */ |
4033 | 0 | foreach_node(Bitmapset, attrs, forced_null_vars) |
4034 | 0 | { |
4035 | 0 | Bitmapset *nonnull_attrs; |
4036 | |
|
4037 | 0 | varno++; |
4038 | | |
4039 | | /* Beyond the end of nonnullable_vars there is nothing left to prove */ |
4040 | 0 | if (varno >= list_length(nonnullable_vars)) |
4041 | 0 | break; |
4042 | | |
4043 | | /* Skip empty bitmaps */ |
4044 | 0 | if (bms_is_empty(attrs)) |
4045 | 0 | continue; |
4046 | | |
4047 | | /* Skip Vars that do not belong to the target relations */ |
4048 | 0 | if (!bms_is_member(varno, state->relids)) |
4049 | 0 | continue; |
4050 | | |
4051 | | /* Get what the quals prove non-null for this relation, if anything */ |
4052 | 0 | nonnull_attrs = list_nth_node(Bitmapset, nonnullable_vars, varno); |
4053 | | |
4054 | | /* |
4055 | | * A proof for the whole-row attribute refutes nothing: it shows only |
4056 | | * that the composite datum is non-null, and such a datum can still |
4057 | | * have all columns NULL. Discard it up front. |
4058 | | */ |
4059 | 0 | nonnull_attrs = bms_del_member(nonnull_attrs, wholerow_attno); |
4060 | | |
4061 | | /* A forced-null attribute that is proven non-null settles it. */ |
4062 | 0 | if (bms_overlap(attrs, nonnull_attrs)) |
4063 | 0 | return true; |
4064 | | |
4065 | | /* |
4066 | | * So does any real column proven non-null, if the whole-row Var is |
4067 | | * forced null: in a matching row (whose whole-row datum is non-null) |
4068 | | * the row-format IS NULL test is true only when every column is NULL. |
4069 | | * System attributes don't count, since they are not part of the row |
4070 | | * value; conveniently they sort below the whole-row attribute in the |
4071 | | * bitmap. |
4072 | | */ |
4073 | 0 | if (bms_is_member(wholerow_attno, attrs) && |
4074 | 0 | bms_next_member(nonnull_attrs, wholerow_attno) >= 0) |
4075 | 0 | return true; |
4076 | 0 | } |
4077 | | |
4078 | | /* |
4079 | | * Otherwise, check if any forced-null var is defined NOT NULL by table |
4080 | | * constraints. |
4081 | | */ |
4082 | 0 | return forced_null_var_is_attnotnull(root, forced_null_vars, state); |
4083 | 0 | } |
4084 | | |
4085 | | |
4086 | | /* |
4087 | | * remove_useless_result_rtes |
4088 | | * Attempt to remove RTE_RESULT RTEs from the join tree. |
4089 | | * Also, elide single-child FromExprs where possible. |
4090 | | * |
4091 | | * We can remove RTE_RESULT entries from the join tree using the knowledge |
4092 | | * that RTE_RESULT returns exactly one row and has no output columns. Hence, |
4093 | | * if one is inner-joined to anything else, we can delete it. Optimizations |
4094 | | * are also possible for some outer-join cases, as detailed below. |
4095 | | * |
4096 | | * This pass also replaces single-child FromExprs with their child node |
4097 | | * where possible. It's appropriate to do that here and not earlier because |
4098 | | * RTE_RESULT removal might reduce a multiple-child FromExpr to have only one |
4099 | | * child. We can remove such a FromExpr if its quals are empty, or if it's |
4100 | | * semantically valid to merge the quals into those of the parent node. |
4101 | | * While removing unnecessary join tree nodes has some micro-efficiency value, |
4102 | | * the real reason to do this is to eliminate cases where the nullable side of |
4103 | | * an outer join node is a FromExpr whose single child is another outer join. |
4104 | | * To correctly determine whether the two outer joins can commute, |
4105 | | * deconstruct_jointree() must treat any quals of such a FromExpr as being |
4106 | | * degenerate quals of the upper outer join. The best way to do that is to |
4107 | | * make them actually *be* quals of the upper join, by dropping the FromExpr |
4108 | | * and hoisting the quals up into the upper join's quals. (Note that there is |
4109 | | * no hazard when the intermediate FromExpr has multiple children, since then |
4110 | | * it represents an inner join that cannot commute with the upper outer join.) |
4111 | | * As long as we have to do that, we might as well elide such FromExprs |
4112 | | * everywhere. |
4113 | | * |
4114 | | * Some of these optimizations depend on recognizing empty (constant-true) |
4115 | | * quals for FromExprs and JoinExprs. That makes it useful to apply this |
4116 | | * optimization pass after expression preprocessing, since that will have |
4117 | | * eliminated constant-true quals, allowing more cases to be recognized as |
4118 | | * optimizable. What's more, the usual reason for an RTE_RESULT to be present |
4119 | | * is that we pulled up a subquery or VALUES clause, thus very possibly |
4120 | | * replacing Vars with constants, making it more likely that a qual can be |
4121 | | * reduced to constant true. Also, because some optimizations depend on |
4122 | | * the outer-join type, it's best to have done reduce_outer_joins() first. |
4123 | | * |
4124 | | * A PlaceHolderVar referencing an RTE_RESULT RTE poses an obstacle to this |
4125 | | * process: we must remove the RTE_RESULT's relid from the PHV's phrels, but |
4126 | | * we must not reduce the phrels set to empty. If that would happen, and |
4127 | | * the RTE_RESULT is an immediate child of an outer join, we have to give up |
4128 | | * and not remove the RTE_RESULT: there is noplace else to evaluate the |
4129 | | * PlaceHolderVar. (That is, in such cases the RTE_RESULT *does* have output |
4130 | | * columns.) But if the RTE_RESULT is an immediate child of an inner join, |
4131 | | * we can usually change the PlaceHolderVar's phrels so as to evaluate it at |
4132 | | * the inner join instead. This is OK because we really only care that PHVs |
4133 | | * are evaluated above or below the correct outer joins. We can't, however, |
4134 | | * postpone the evaluation of a PHV to above where it is used; so there are |
4135 | | * some checks below on whether output PHVs are laterally referenced in the |
4136 | | * other join input rel(s). |
4137 | | * |
4138 | | * We used to try to do this work as part of pull_up_subqueries() where the |
4139 | | * potentially-optimizable cases get introduced; but it's way simpler, and |
4140 | | * more effective, to do it separately. |
4141 | | */ |
4142 | | void |
4143 | | remove_useless_result_rtes(PlannerInfo *root) |
4144 | 0 | { |
4145 | 0 | Relids baserels = NULL; |
4146 | 0 | Relids dropped_outer_joins = NULL; |
4147 | 0 | ListCell *cell; |
4148 | | |
4149 | | /* |
4150 | | * We'll need the set of baserels in the jointree to perform |
4151 | | * find_dependent_phvs() checks. But if there are no PHVs anywhere in the |
4152 | | * query, those checks are no-ops, so we can skip the work. |
4153 | | */ |
4154 | 0 | if (root->glob->lastPHId != 0) |
4155 | 0 | baserels = get_relids_in_jointree((Node *) root->parse->jointree, |
4156 | 0 | false, false); |
4157 | | |
4158 | | /* Top level of jointree must always be a FromExpr */ |
4159 | 0 | Assert(IsA(root->parse->jointree, FromExpr)); |
4160 | | /* Recurse ... */ |
4161 | 0 | root->parse->jointree = (FromExpr *) |
4162 | 0 | remove_useless_results_recurse(root, |
4163 | 0 | (Node *) root->parse->jointree, |
4164 | 0 | baserels, |
4165 | 0 | NULL, |
4166 | 0 | &dropped_outer_joins); |
4167 | | /* We should still have a FromExpr */ |
4168 | 0 | Assert(IsA(root->parse->jointree, FromExpr)); |
4169 | | |
4170 | | /* |
4171 | | * If we removed any outer-join nodes from the jointree, run around and |
4172 | | * remove references to those joins as nulling rels. (There could be such |
4173 | | * references in PHVs that we pulled up out of the original subquery that |
4174 | | * the RESULT rel replaced. This is kosher on the grounds that we now |
4175 | | * know that such an outer join wouldn't really have nulled anything.) We |
4176 | | * don't do this during the main recursion, for simplicity and because we |
4177 | | * can handle all such joins in a single pass over the parse tree. |
4178 | | */ |
4179 | 0 | if (!bms_is_empty(dropped_outer_joins)) |
4180 | 0 | { |
4181 | 0 | root->parse = (Query *) |
4182 | 0 | remove_nulling_relids((Node *) root->parse, |
4183 | 0 | dropped_outer_joins, |
4184 | 0 | NULL); |
4185 | | /* There could be references in the append_rel_list, too */ |
4186 | 0 | root->append_rel_list = (List *) |
4187 | 0 | remove_nulling_relids((Node *) root->append_rel_list, |
4188 | 0 | dropped_outer_joins, |
4189 | 0 | NULL); |
4190 | 0 | } |
4191 | | |
4192 | | /* |
4193 | | * Remove any PlanRowMark referencing an RTE_RESULT RTE. We obviously |
4194 | | * must do that for any RTE_RESULT that we just removed. But one for a |
4195 | | * RTE that we did not remove can be dropped anyway: since the RTE has |
4196 | | * only one possible output row, there is no need for EPQ to mark and |
4197 | | * restore that row. |
4198 | | * |
4199 | | * It's necessary, not optional, to remove the PlanRowMark for a surviving |
4200 | | * RTE_RESULT RTE; otherwise we'll generate a whole-row Var for the |
4201 | | * RTE_RESULT, which the executor has no support for. |
4202 | | */ |
4203 | 0 | foreach(cell, root->rowMarks) |
4204 | 0 | { |
4205 | 0 | PlanRowMark *rc = (PlanRowMark *) lfirst(cell); |
4206 | |
|
4207 | 0 | if (rt_fetch(rc->rti, root->parse->rtable)->rtekind == RTE_RESULT) |
4208 | 0 | root->rowMarks = foreach_delete_current(root->rowMarks, cell); |
4209 | 0 | } |
4210 | 0 | } |
4211 | | |
4212 | | /* |
4213 | | * remove_useless_results_recurse |
4214 | | * Recursive guts of remove_useless_result_rtes. |
4215 | | * |
4216 | | * This recursively processes the jointree and returns a modified jointree. |
4217 | | * In addition, the RT indexes of any removed outer-join nodes are added to |
4218 | | * *dropped_outer_joins. |
4219 | | * |
4220 | | * jtnode is the current jointree node. If it could be valid to merge |
4221 | | * its quals into those of the parent node, parent_quals should point to |
4222 | | * the parent's quals list; otherwise, pass NULL for parent_quals. |
4223 | | * (Note that in some cases, parent_quals points to the quals of a parent |
4224 | | * more than one level up in the tree.) |
4225 | | * |
4226 | | * baserels is the set of base (non-join) RT indexes in the whole jointree; |
4227 | | * it can be NULL if the query contains no PHVs. |
4228 | | */ |
4229 | | static Node * |
4230 | | remove_useless_results_recurse(PlannerInfo *root, Node *jtnode, |
4231 | | Relids baserels, |
4232 | | Node **parent_quals, |
4233 | | Relids *dropped_outer_joins) |
4234 | 0 | { |
4235 | 0 | Assert(jtnode != NULL); |
4236 | 0 | if (IsA(jtnode, RangeTblRef)) |
4237 | 0 | { |
4238 | | /* Can't immediately do anything with a RangeTblRef */ |
4239 | 0 | } |
4240 | 0 | else if (IsA(jtnode, FromExpr)) |
4241 | 0 | { |
4242 | 0 | FromExpr *f = (FromExpr *) jtnode; |
4243 | 0 | Relids result_relids = NULL; |
4244 | 0 | ListCell *cell; |
4245 | | |
4246 | | /* |
4247 | | * We can drop RTE_RESULT rels from the fromlist so long as at least |
4248 | | * one child remains, since joining to a one-row table changes |
4249 | | * nothing. (But we can't drop a RTE_RESULT that computes PHV(s) that |
4250 | | * are needed by some sibling. The cleanup transformation below would |
4251 | | * reassign the PHVs to be computed at the join, which is too late for |
4252 | | * the sibling's use.) The easiest way to mechanize this rule is to |
4253 | | * modify the list in-place. |
4254 | | */ |
4255 | 0 | foreach(cell, f->fromlist) |
4256 | 0 | { |
4257 | 0 | Node *child = (Node *) lfirst(cell); |
4258 | 0 | int varno; |
4259 | | |
4260 | | /* Recursively transform child, allowing it to push up quals ... */ |
4261 | 0 | child = remove_useless_results_recurse(root, child, |
4262 | 0 | baserels, |
4263 | 0 | &f->quals, |
4264 | 0 | dropped_outer_joins); |
4265 | | /* ... and stick it back into the tree */ |
4266 | 0 | lfirst(cell) = child; |
4267 | | |
4268 | | /* |
4269 | | * If it's an RTE_RESULT with at least one sibling, and no sibling |
4270 | | * references dependent PHVs, we can drop it. We don't yet know |
4271 | | * what the inner join's final relid set will be, so postpone |
4272 | | * cleanup of PHVs etc till after this loop. |
4273 | | */ |
4274 | 0 | if (list_length(f->fromlist) > 1 && |
4275 | 0 | (varno = get_result_relid(root, child)) != 0 && |
4276 | 0 | !find_dependent_phvs_in_jointree(root, (Node *) f, varno, |
4277 | 0 | baserels)) |
4278 | 0 | { |
4279 | 0 | f->fromlist = foreach_delete_current(f->fromlist, cell); |
4280 | 0 | result_relids = bms_add_member(result_relids, varno); |
4281 | 0 | } |
4282 | 0 | } |
4283 | | |
4284 | | /* |
4285 | | * Clean up if we dropped any RTE_RESULT RTEs. This is a bit |
4286 | | * inefficient if there's more than one, but it seems better to |
4287 | | * optimize the support code for the single-relid case. |
4288 | | */ |
4289 | 0 | if (result_relids) |
4290 | 0 | { |
4291 | 0 | int varno = -1; |
4292 | |
|
4293 | 0 | while ((varno = bms_next_member(result_relids, varno)) >= 0) |
4294 | 0 | remove_result_refs(root, varno, (Node *) f); |
4295 | 0 | } |
4296 | | |
4297 | | /* |
4298 | | * If the FromExpr now has only one child, see if we can elide it. |
4299 | | * This is always valid if there are no quals, except at the top of |
4300 | | * the jointree (since Query.jointree is required to point to a |
4301 | | * FromExpr). Otherwise, we can do it if we can push the quals up to |
4302 | | * the parent node. |
4303 | | * |
4304 | | * Note: while it would not be terribly hard to generalize this |
4305 | | * transformation to merge multi-child FromExprs into their parent |
4306 | | * FromExpr, that risks making the parent join too expensive to plan. |
4307 | | * We leave it to later processing to decide heuristically whether |
4308 | | * that's a good idea. Pulling up a single child is always OK, |
4309 | | * however. |
4310 | | */ |
4311 | 0 | if (list_length(f->fromlist) == 1 && |
4312 | 0 | f != root->parse->jointree && |
4313 | 0 | (f->quals == NULL || parent_quals != NULL)) |
4314 | 0 | { |
4315 | | /* |
4316 | | * Merge any quals up to parent. They should be in implicit-AND |
4317 | | * format by now, so we just need to concatenate lists. Put the |
4318 | | * child quals at the front, on the grounds that they should |
4319 | | * nominally be evaluated earlier. |
4320 | | */ |
4321 | 0 | if (f->quals != NULL) |
4322 | 0 | *parent_quals = (Node *) |
4323 | 0 | list_concat(castNode(List, f->quals), |
4324 | 0 | castNode(List, *parent_quals)); |
4325 | 0 | return (Node *) linitial(f->fromlist); |
4326 | 0 | } |
4327 | 0 | } |
4328 | 0 | else if (IsA(jtnode, JoinExpr)) |
4329 | 0 | { |
4330 | 0 | JoinExpr *j = (JoinExpr *) jtnode; |
4331 | 0 | int varno; |
4332 | | |
4333 | | /* |
4334 | | * First, recurse. We can absorb pushed-up FromExpr quals from either |
4335 | | * child into this node if the jointype is INNER, since then this is |
4336 | | * equivalent to a FromExpr. When the jointype is LEFT, we can absorb |
4337 | | * quals from the RHS child into the current node, as they're |
4338 | | * essentially degenerate quals of the outer join. Moreover, if we've |
4339 | | * been passed down a parent_quals pointer then we can allow quals of |
4340 | | * the LHS child to be absorbed into the parent. (This is important |
4341 | | * to ensure we remove single-child FromExprs immediately below |
4342 | | * commutable left joins.) For other jointypes, we can't move child |
4343 | | * quals up, or at least there's no particular reason to. |
4344 | | */ |
4345 | 0 | j->larg = remove_useless_results_recurse(root, j->larg, |
4346 | 0 | baserels, |
4347 | 0 | (j->jointype == JOIN_INNER) ? |
4348 | 0 | &j->quals : |
4349 | 0 | (j->jointype == JOIN_LEFT) ? |
4350 | 0 | parent_quals : NULL, |
4351 | 0 | dropped_outer_joins); |
4352 | 0 | j->rarg = remove_useless_results_recurse(root, j->rarg, |
4353 | 0 | baserels, |
4354 | 0 | (j->jointype == JOIN_INNER || |
4355 | 0 | j->jointype == JOIN_LEFT) ? |
4356 | 0 | &j->quals : NULL, |
4357 | 0 | dropped_outer_joins); |
4358 | | |
4359 | | /* Apply join-type-specific optimization rules */ |
4360 | 0 | switch (j->jointype) |
4361 | 0 | { |
4362 | 0 | case JOIN_INNER: |
4363 | | |
4364 | | /* |
4365 | | * An inner join is equivalent to a FromExpr, so if either |
4366 | | * side was simplified to an RTE_RESULT rel, we can replace |
4367 | | * the join with a FromExpr with just the other side. |
4368 | | * Furthermore, we can elide that FromExpr according to the |
4369 | | * same rules as above. |
4370 | | * |
4371 | | * Just as in the FromExpr case, we can't simplify if the |
4372 | | * other input rel references any PHVs that are marked as to |
4373 | | * be evaluated at the RTE_RESULT rel, because we can't |
4374 | | * postpone their evaluation in that case. But we only have |
4375 | | * to check this in cases where it's syntactically legal for |
4376 | | * the other input to have a LATERAL reference to the |
4377 | | * RTE_RESULT rel. Only RHSes of inner and left joins are |
4378 | | * allowed to have such refs. |
4379 | | */ |
4380 | 0 | if ((varno = get_result_relid(root, j->larg)) != 0 && |
4381 | 0 | !find_dependent_phvs_in_jointree(root, j->rarg, varno, |
4382 | 0 | baserels)) |
4383 | 0 | { |
4384 | 0 | remove_result_refs(root, varno, j->rarg); |
4385 | 0 | if (j->quals != NULL && parent_quals == NULL) |
4386 | 0 | jtnode = (Node *) |
4387 | 0 | makeFromExpr(list_make1(j->rarg), j->quals); |
4388 | 0 | else |
4389 | 0 | { |
4390 | | /* Merge any quals up to parent */ |
4391 | 0 | if (j->quals != NULL) |
4392 | 0 | *parent_quals = (Node *) |
4393 | 0 | list_concat(castNode(List, j->quals), |
4394 | 0 | castNode(List, *parent_quals)); |
4395 | 0 | jtnode = j->rarg; |
4396 | 0 | } |
4397 | 0 | } |
4398 | 0 | else if ((varno = get_result_relid(root, j->rarg)) != 0) |
4399 | 0 | { |
4400 | 0 | remove_result_refs(root, varno, j->larg); |
4401 | 0 | if (j->quals != NULL && parent_quals == NULL) |
4402 | 0 | jtnode = (Node *) |
4403 | 0 | makeFromExpr(list_make1(j->larg), j->quals); |
4404 | 0 | else |
4405 | 0 | { |
4406 | | /* Merge any quals up to parent */ |
4407 | 0 | if (j->quals != NULL) |
4408 | 0 | *parent_quals = (Node *) |
4409 | 0 | list_concat(castNode(List, j->quals), |
4410 | 0 | castNode(List, *parent_quals)); |
4411 | 0 | jtnode = j->larg; |
4412 | 0 | } |
4413 | 0 | } |
4414 | 0 | break; |
4415 | 0 | case JOIN_LEFT: |
4416 | | |
4417 | | /* |
4418 | | * We can simplify this case if the RHS is an RTE_RESULT, with |
4419 | | * two different possibilities: |
4420 | | * |
4421 | | * If the qual is empty (JOIN ON TRUE), then the join can be |
4422 | | * strength-reduced to a plain inner join, since each LHS row |
4423 | | * necessarily has exactly one join partner. So we can always |
4424 | | * discard the RHS, much as in the JOIN_INNER case above. |
4425 | | * (Again, the LHS could not contain a lateral reference to |
4426 | | * the RHS.) |
4427 | | * |
4428 | | * Otherwise, it's still true that each LHS row should be |
4429 | | * returned exactly once, and since the RHS returns no columns |
4430 | | * (unless there are PHVs that have to be evaluated there), we |
4431 | | * don't much care if it's null-extended or not. So in this |
4432 | | * case also, we can just ignore the qual and discard the left |
4433 | | * join. |
4434 | | */ |
4435 | 0 | if ((varno = get_result_relid(root, j->rarg)) != 0 && |
4436 | 0 | (j->quals == NULL || |
4437 | 0 | !find_dependent_phvs(root, varno, baserels))) |
4438 | 0 | { |
4439 | 0 | remove_result_refs(root, varno, j->larg); |
4440 | 0 | *dropped_outer_joins = bms_add_member(*dropped_outer_joins, |
4441 | 0 | j->rtindex); |
4442 | 0 | jtnode = j->larg; |
4443 | 0 | } |
4444 | 0 | break; |
4445 | 0 | case JOIN_SEMI: |
4446 | | |
4447 | | /* |
4448 | | * We may simplify this case if the RHS is an RTE_RESULT; the |
4449 | | * join qual becomes effectively just a filter qual for the |
4450 | | * LHS, since we should either return the LHS row or not. The |
4451 | | * filter clause must go into a new FromExpr if we can't push |
4452 | | * it up to the parent. |
4453 | | * |
4454 | | * There is a fine point about PHVs that are supposed to be |
4455 | | * evaluated at the RHS. Such PHVs could only appear in the |
4456 | | * semijoin's qual, since the rest of the query cannot |
4457 | | * reference any outputs of the semijoin's RHS. Therefore, |
4458 | | * they can't actually go to null before being examined, and |
4459 | | * it'd be OK to just remove the PHV wrapping. We don't have |
4460 | | * infrastructure for that, but remove_result_refs() will |
4461 | | * relabel them as to be evaluated at the LHS, which is fine. |
4462 | | * |
4463 | | * Also, we don't need to worry about removing traces of the |
4464 | | * join's rtindex, since it hasn't got one. |
4465 | | */ |
4466 | 0 | if ((varno = get_result_relid(root, j->rarg)) != 0) |
4467 | 0 | { |
4468 | 0 | Assert(j->rtindex == 0); |
4469 | 0 | remove_result_refs(root, varno, j->larg); |
4470 | 0 | if (j->quals != NULL && parent_quals == NULL) |
4471 | 0 | jtnode = (Node *) |
4472 | 0 | makeFromExpr(list_make1(j->larg), j->quals); |
4473 | 0 | else |
4474 | 0 | { |
4475 | | /* Merge any quals up to parent */ |
4476 | 0 | if (j->quals != NULL) |
4477 | 0 | *parent_quals = (Node *) |
4478 | 0 | list_concat(castNode(List, j->quals), |
4479 | 0 | castNode(List, *parent_quals)); |
4480 | 0 | jtnode = j->larg; |
4481 | 0 | } |
4482 | 0 | } |
4483 | 0 | break; |
4484 | 0 | case JOIN_FULL: |
4485 | 0 | case JOIN_ANTI: |
4486 | | /* We have no special smarts for these cases */ |
4487 | 0 | break; |
4488 | 0 | default: |
4489 | | /* Note: JOIN_RIGHT should be gone at this point */ |
4490 | 0 | elog(ERROR, "unrecognized join type: %d", |
4491 | 0 | (int) j->jointype); |
4492 | 0 | break; |
4493 | 0 | } |
4494 | 0 | } |
4495 | 0 | else |
4496 | 0 | elog(ERROR, "unrecognized node type: %d", |
4497 | 0 | (int) nodeTag(jtnode)); |
4498 | 0 | return jtnode; |
4499 | 0 | } |
4500 | | |
4501 | | /* |
4502 | | * get_result_relid |
4503 | | * If jtnode is a RangeTblRef for an RTE_RESULT RTE, return its relid; |
4504 | | * otherwise return 0. |
4505 | | */ |
4506 | | static int |
4507 | | get_result_relid(PlannerInfo *root, Node *jtnode) |
4508 | 0 | { |
4509 | 0 | int varno; |
4510 | |
|
4511 | 0 | if (!IsA(jtnode, RangeTblRef)) |
4512 | 0 | return 0; |
4513 | 0 | varno = ((RangeTblRef *) jtnode)->rtindex; |
4514 | 0 | if (rt_fetch(varno, root->parse->rtable)->rtekind != RTE_RESULT) |
4515 | 0 | return 0; |
4516 | 0 | return varno; |
4517 | 0 | } |
4518 | | |
4519 | | /* |
4520 | | * remove_result_refs |
4521 | | * Helper routine for dropping an unneeded RTE_RESULT RTE. |
4522 | | * |
4523 | | * This doesn't physically remove the RTE from the jointree, because that's |
4524 | | * more easily handled in remove_useless_results_recurse. What it does do |
4525 | | * is the necessary cleanup in the rest of the tree: we must adjust any PHVs |
4526 | | * that may reference the RTE. Be sure to call this at a point where the |
4527 | | * jointree is valid (no disconnected nodes). |
4528 | | * |
4529 | | * Note that we don't need to process the append_rel_list, since RTEs |
4530 | | * referenced directly in the jointree won't be appendrel members. |
4531 | | * |
4532 | | * varno is the RTE_RESULT's relid. |
4533 | | * newjtloc is the jointree location at which any PHVs referencing the |
4534 | | * RTE_RESULT should be evaluated instead. |
4535 | | */ |
4536 | | static void |
4537 | | remove_result_refs(PlannerInfo *root, int varno, Node *newjtloc) |
4538 | 0 | { |
4539 | | /* Fix up PlaceHolderVars as needed */ |
4540 | | /* If there are no PHVs anywhere, we can skip this bit */ |
4541 | 0 | if (root->glob->lastPHId != 0) |
4542 | 0 | { |
4543 | 0 | Relids subrelids; |
4544 | |
|
4545 | 0 | subrelids = get_relids_in_jointree(newjtloc, true, false); |
4546 | 0 | Assert(!bms_is_empty(subrelids)); |
4547 | 0 | substitute_phv_relids((Node *) root->parse, varno, subrelids); |
4548 | 0 | fix_append_rel_relids(root, varno, subrelids); |
4549 | 0 | } |
4550 | | |
4551 | | /* |
4552 | | * We also need to remove any PlanRowMark referencing the RTE, but we |
4553 | | * postpone that work until we return to remove_useless_result_rtes. |
4554 | | */ |
4555 | 0 | } |
4556 | | |
4557 | | |
4558 | | /* |
4559 | | * find_dependent_phvs - are there any PlaceHolderVars whose base relids are |
4560 | | * exactly the given varno? |
4561 | | * |
4562 | | * We ignore outer-join relids present in a PHV's phrels, by intersecting |
4563 | | * with the caller-supplied "baserels" set. This is necessary in part |
4564 | | * because some of the OJ relids may be stale, that is we may have |
4565 | | * already decided to remove those joins in remove_useless_result_rtes |
4566 | | * and not yet have cleaned their relid bits out of upper PHVs. |
4567 | | * But in general, it's the set of baserels that identify possible places |
4568 | | * to evaluate a PHV, and we mustn't let that go to empty. (The caller is |
4569 | | * allowed to pass baserels as NULL if the query contains no PHVs at all, |
4570 | | * since then there is no work to do anyway.) |
4571 | | * |
4572 | | * find_dependent_phvs should be used when we want to see if there are |
4573 | | * any such PHVs anywhere in the Query. Another use-case is to see if |
4574 | | * a subtree of the join tree contains such PHVs; but for that, we have |
4575 | | * to look not only at the join tree nodes themselves but at the |
4576 | | * referenced RTEs. For that, use find_dependent_phvs_in_jointree. |
4577 | | */ |
4578 | | |
4579 | | typedef struct |
4580 | | { |
4581 | | Relids relids; /* target relid, represented as a relid set */ |
4582 | | Relids baserels; /* base RT indexes in query, NULL if no PHVs */ |
4583 | | int sublevels_up; /* current nesting level */ |
4584 | | } find_dependent_phvs_context; |
4585 | | |
4586 | | static bool |
4587 | | find_dependent_phvs_walker(Node *node, |
4588 | | find_dependent_phvs_context *context) |
4589 | 0 | { |
4590 | 0 | if (node == NULL) |
4591 | 0 | return false; |
4592 | 0 | if (IsA(node, PlaceHolderVar)) |
4593 | 0 | { |
4594 | 0 | PlaceHolderVar *phv = (PlaceHolderVar *) node; |
4595 | |
|
4596 | 0 | if (phv->phlevelsup == context->sublevels_up) |
4597 | 0 | { |
4598 | 0 | Relids phbaserels = bms_intersect(phv->phrels, |
4599 | 0 | context->baserels); |
4600 | 0 | bool match = bms_equal(context->relids, phbaserels); |
4601 | |
|
4602 | 0 | bms_free(phbaserels); |
4603 | 0 | if (match) |
4604 | 0 | return true; |
4605 | 0 | } |
4606 | | /* fall through to examine children */ |
4607 | 0 | } |
4608 | 0 | if (IsA(node, Query)) |
4609 | 0 | { |
4610 | | /* Recurse into subselects */ |
4611 | 0 | bool result; |
4612 | |
|
4613 | 0 | context->sublevels_up++; |
4614 | 0 | result = query_tree_walker((Query *) node, |
4615 | 0 | find_dependent_phvs_walker, |
4616 | 0 | context, 0); |
4617 | 0 | context->sublevels_up--; |
4618 | 0 | return result; |
4619 | 0 | } |
4620 | | /* Shouldn't need to handle most planner auxiliary nodes here */ |
4621 | 0 | Assert(!IsA(node, SpecialJoinInfo)); |
4622 | 0 | Assert(!IsA(node, PlaceHolderInfo)); |
4623 | 0 | Assert(!IsA(node, MinMaxAggInfo)); |
4624 | |
|
4625 | 0 | return expression_tree_walker(node, find_dependent_phvs_walker, context); |
4626 | 0 | } |
4627 | | |
4628 | | static bool |
4629 | | find_dependent_phvs(PlannerInfo *root, int varno, Relids baserels) |
4630 | 0 | { |
4631 | 0 | find_dependent_phvs_context context; |
4632 | | |
4633 | | /* If there are no PHVs anywhere, we needn't work hard */ |
4634 | 0 | if (root->glob->lastPHId == 0) |
4635 | 0 | return false; |
4636 | | |
4637 | 0 | context.relids = bms_make_singleton(varno); |
4638 | 0 | context.baserels = baserels; |
4639 | 0 | context.sublevels_up = 0; |
4640 | |
|
4641 | 0 | if (query_tree_walker(root->parse, find_dependent_phvs_walker, &context, 0)) |
4642 | 0 | return true; |
4643 | | /* The append_rel_list could be populated already, so check it too */ |
4644 | 0 | if (expression_tree_walker((Node *) root->append_rel_list, |
4645 | 0 | find_dependent_phvs_walker, |
4646 | 0 | &context)) |
4647 | 0 | return true; |
4648 | 0 | return false; |
4649 | 0 | } |
4650 | | |
4651 | | static bool |
4652 | | find_dependent_phvs_in_jointree(PlannerInfo *root, Node *node, int varno, |
4653 | | Relids baserels) |
4654 | 0 | { |
4655 | 0 | find_dependent_phvs_context context; |
4656 | 0 | Relids subrelids; |
4657 | 0 | int relid; |
4658 | | |
4659 | | /* If there are no PHVs anywhere, we needn't work hard */ |
4660 | 0 | if (root->glob->lastPHId == 0) |
4661 | 0 | return false; |
4662 | | |
4663 | 0 | context.relids = bms_make_singleton(varno); |
4664 | 0 | context.baserels = baserels; |
4665 | 0 | context.sublevels_up = 0; |
4666 | | |
4667 | | /* |
4668 | | * See if the jointree fragment itself contains references (in join quals) |
4669 | | */ |
4670 | 0 | if (find_dependent_phvs_walker(node, &context)) |
4671 | 0 | return true; |
4672 | | |
4673 | | /* |
4674 | | * Otherwise, identify the set of referenced RTEs (we can ignore joins, |
4675 | | * since they should be flattened already, so their join alias lists no |
4676 | | * longer matter), and tediously check each RTE. We can ignore RTEs that |
4677 | | * are not marked LATERAL, though, since they couldn't possibly contain |
4678 | | * any cross-references to other RTEs. |
4679 | | */ |
4680 | 0 | subrelids = get_relids_in_jointree(node, false, false); |
4681 | 0 | relid = -1; |
4682 | 0 | while ((relid = bms_next_member(subrelids, relid)) >= 0) |
4683 | 0 | { |
4684 | 0 | RangeTblEntry *rte = rt_fetch(relid, root->parse->rtable); |
4685 | |
|
4686 | 0 | if (rte->lateral && |
4687 | 0 | range_table_entry_walker(rte, find_dependent_phvs_walker, &context, 0)) |
4688 | 0 | return true; |
4689 | 0 | } |
4690 | | |
4691 | 0 | return false; |
4692 | 0 | } |
4693 | | |
4694 | | /* |
4695 | | * substitute_phv_relids - adjust PlaceHolderVar relid sets after pulling up |
4696 | | * a subquery or removing an RTE_RESULT jointree item |
4697 | | * |
4698 | | * Find any PlaceHolderVar nodes in the given tree that reference the |
4699 | | * pulled-up relid, and change them to reference the replacement relid(s). |
4700 | | * |
4701 | | * NOTE: although this has the form of a walker, we cheat and modify the |
4702 | | * nodes in-place. This should be OK since the tree was copied by |
4703 | | * pullup_replace_vars earlier. Avoid scribbling on the original values of |
4704 | | * the bitmapsets, though, because expression_tree_mutator doesn't copy those. |
4705 | | */ |
4706 | | |
4707 | | typedef struct |
4708 | | { |
4709 | | int varno; |
4710 | | int sublevels_up; |
4711 | | Relids subrelids; |
4712 | | } substitute_phv_relids_context; |
4713 | | |
4714 | | static bool |
4715 | | substitute_phv_relids_walker(Node *node, |
4716 | | substitute_phv_relids_context *context) |
4717 | 0 | { |
4718 | 0 | if (node == NULL) |
4719 | 0 | return false; |
4720 | 0 | if (IsA(node, PlaceHolderVar)) |
4721 | 0 | { |
4722 | 0 | PlaceHolderVar *phv = (PlaceHolderVar *) node; |
4723 | |
|
4724 | 0 | if (phv->phlevelsup == context->sublevels_up && |
4725 | 0 | bms_is_member(context->varno, phv->phrels)) |
4726 | 0 | { |
4727 | 0 | phv->phrels = bms_union(phv->phrels, |
4728 | 0 | context->subrelids); |
4729 | 0 | phv->phrels = bms_del_member(phv->phrels, |
4730 | 0 | context->varno); |
4731 | | /* Assert we haven't broken the PHV */ |
4732 | 0 | Assert(!bms_is_empty(phv->phrels)); |
4733 | 0 | } |
4734 | | /* fall through to examine children */ |
4735 | 0 | } |
4736 | 0 | if (IsA(node, Query)) |
4737 | 0 | { |
4738 | | /* Recurse into subselects */ |
4739 | 0 | bool result; |
4740 | |
|
4741 | 0 | context->sublevels_up++; |
4742 | 0 | result = query_tree_walker((Query *) node, |
4743 | 0 | substitute_phv_relids_walker, |
4744 | 0 | context, 0); |
4745 | 0 | context->sublevels_up--; |
4746 | 0 | return result; |
4747 | 0 | } |
4748 | | /* Shouldn't need to handle planner auxiliary nodes here */ |
4749 | 0 | Assert(!IsA(node, SpecialJoinInfo)); |
4750 | 0 | Assert(!IsA(node, AppendRelInfo)); |
4751 | 0 | Assert(!IsA(node, PlaceHolderInfo)); |
4752 | 0 | Assert(!IsA(node, MinMaxAggInfo)); |
4753 | |
|
4754 | 0 | return expression_tree_walker(node, substitute_phv_relids_walker, context); |
4755 | 0 | } |
4756 | | |
4757 | | static void |
4758 | | substitute_phv_relids(Node *node, int varno, Relids subrelids) |
4759 | 0 | { |
4760 | 0 | substitute_phv_relids_context context; |
4761 | |
|
4762 | 0 | context.varno = varno; |
4763 | 0 | context.sublevels_up = 0; |
4764 | 0 | context.subrelids = subrelids; |
4765 | | |
4766 | | /* |
4767 | | * Must be prepared to start with a Query or a bare expression tree. |
4768 | | */ |
4769 | 0 | query_or_expression_tree_walker(node, |
4770 | 0 | substitute_phv_relids_walker, |
4771 | 0 | &context, |
4772 | 0 | 0); |
4773 | 0 | } |
4774 | | |
4775 | | /* |
4776 | | * fix_append_rel_relids: update RT-index fields of AppendRelInfo nodes |
4777 | | * |
4778 | | * When we pull up a subquery, any AppendRelInfo references to the subquery's |
4779 | | * RT index have to be replaced by the substituted relid (and there had better |
4780 | | * be only one). We also need to apply substitute_phv_relids to their |
4781 | | * translated_vars lists, since those might contain PlaceHolderVars. |
4782 | | * |
4783 | | * We assume we may modify the AppendRelInfo nodes in-place. |
4784 | | */ |
4785 | | static void |
4786 | | fix_append_rel_relids(PlannerInfo *root, int varno, Relids subrelids) |
4787 | 0 | { |
4788 | 0 | ListCell *l; |
4789 | 0 | int subvarno = -1; |
4790 | | |
4791 | | /* |
4792 | | * We only want to extract the member relid once, but we mustn't fail |
4793 | | * immediately if there are multiple members; it could be that none of the |
4794 | | * AppendRelInfo nodes refer to it. So compute it on first use. Note that |
4795 | | * bms_singleton_member will complain if set is not singleton. |
4796 | | */ |
4797 | 0 | foreach(l, root->append_rel_list) |
4798 | 0 | { |
4799 | 0 | AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(l); |
4800 | | |
4801 | | /* The parent_relid shouldn't ever be a pullup target */ |
4802 | 0 | Assert(appinfo->parent_relid != varno); |
4803 | |
|
4804 | 0 | if (appinfo->child_relid == varno) |
4805 | 0 | { |
4806 | 0 | if (subvarno < 0) |
4807 | 0 | subvarno = bms_singleton_member(subrelids); |
4808 | 0 | appinfo->child_relid = subvarno; |
4809 | 0 | } |
4810 | | |
4811 | | /* Also fix up any PHVs in its translated vars */ |
4812 | 0 | if (root->glob->lastPHId != 0) |
4813 | 0 | substitute_phv_relids((Node *) appinfo->translated_vars, |
4814 | 0 | varno, subrelids); |
4815 | 0 | } |
4816 | 0 | } |
4817 | | |
4818 | | /* |
4819 | | * get_relids_in_jointree: get set of RT indexes present in a jointree |
4820 | | * |
4821 | | * Base-relation relids are always included in the result. |
4822 | | * If include_outer_joins is true, outer-join RT indexes are included. |
4823 | | * If include_inner_joins is true, inner-join RT indexes are included. |
4824 | | * |
4825 | | * Note that for most purposes in the planner, outer joins are included |
4826 | | * in standard relid sets. Setting include_inner_joins true is only |
4827 | | * appropriate for special purposes during subquery flattening. |
4828 | | */ |
4829 | | Relids |
4830 | | get_relids_in_jointree(Node *jtnode, bool include_outer_joins, |
4831 | | bool include_inner_joins) |
4832 | 0 | { |
4833 | 0 | Relids result = NULL; |
4834 | |
|
4835 | 0 | if (jtnode == NULL) |
4836 | 0 | return result; |
4837 | 0 | if (IsA(jtnode, RangeTblRef)) |
4838 | 0 | { |
4839 | 0 | int varno = ((RangeTblRef *) jtnode)->rtindex; |
4840 | |
|
4841 | 0 | result = bms_make_singleton(varno); |
4842 | 0 | } |
4843 | 0 | else if (IsA(jtnode, FromExpr)) |
4844 | 0 | { |
4845 | 0 | FromExpr *f = (FromExpr *) jtnode; |
4846 | 0 | ListCell *l; |
4847 | |
|
4848 | 0 | foreach(l, f->fromlist) |
4849 | 0 | { |
4850 | 0 | result = bms_join(result, |
4851 | 0 | get_relids_in_jointree(lfirst(l), |
4852 | 0 | include_outer_joins, |
4853 | 0 | include_inner_joins)); |
4854 | 0 | } |
4855 | 0 | } |
4856 | 0 | else if (IsA(jtnode, JoinExpr)) |
4857 | 0 | { |
4858 | 0 | JoinExpr *j = (JoinExpr *) jtnode; |
4859 | |
|
4860 | 0 | result = get_relids_in_jointree(j->larg, |
4861 | 0 | include_outer_joins, |
4862 | 0 | include_inner_joins); |
4863 | 0 | result = bms_join(result, |
4864 | 0 | get_relids_in_jointree(j->rarg, |
4865 | 0 | include_outer_joins, |
4866 | 0 | include_inner_joins)); |
4867 | 0 | if (j->rtindex) |
4868 | 0 | { |
4869 | 0 | if (j->jointype == JOIN_INNER) |
4870 | 0 | { |
4871 | 0 | if (include_inner_joins) |
4872 | 0 | result = bms_add_member(result, j->rtindex); |
4873 | 0 | } |
4874 | 0 | else |
4875 | 0 | { |
4876 | 0 | if (include_outer_joins) |
4877 | 0 | result = bms_add_member(result, j->rtindex); |
4878 | 0 | } |
4879 | 0 | } |
4880 | 0 | } |
4881 | 0 | else |
4882 | 0 | elog(ERROR, "unrecognized node type: %d", |
4883 | 0 | (int) nodeTag(jtnode)); |
4884 | 0 | return result; |
4885 | 0 | } |
4886 | | |
4887 | | /* |
4888 | | * get_relids_for_join: get set of base+OJ RT indexes making up a join |
4889 | | */ |
4890 | | Relids |
4891 | | get_relids_for_join(Query *query, int joinrelid) |
4892 | 0 | { |
4893 | 0 | Node *jtnode; |
4894 | |
|
4895 | 0 | jtnode = find_jointree_node_for_rel((Node *) query->jointree, |
4896 | 0 | joinrelid); |
4897 | 0 | if (!jtnode) |
4898 | 0 | elog(ERROR, "could not find join node %d", joinrelid); |
4899 | 0 | return get_relids_in_jointree(jtnode, true, false); |
4900 | 0 | } |
4901 | | |
4902 | | /* |
4903 | | * find_jointree_node_for_rel: locate jointree node for a base or join RT index |
4904 | | * |
4905 | | * Returns NULL if not found |
4906 | | */ |
4907 | | static Node * |
4908 | | find_jointree_node_for_rel(Node *jtnode, int relid) |
4909 | 0 | { |
4910 | 0 | if (jtnode == NULL) |
4911 | 0 | return NULL; |
4912 | 0 | if (IsA(jtnode, RangeTblRef)) |
4913 | 0 | { |
4914 | 0 | int varno = ((RangeTblRef *) jtnode)->rtindex; |
4915 | |
|
4916 | 0 | if (relid == varno) |
4917 | 0 | return jtnode; |
4918 | 0 | } |
4919 | 0 | else if (IsA(jtnode, FromExpr)) |
4920 | 0 | { |
4921 | 0 | FromExpr *f = (FromExpr *) jtnode; |
4922 | 0 | ListCell *l; |
4923 | |
|
4924 | 0 | foreach(l, f->fromlist) |
4925 | 0 | { |
4926 | 0 | jtnode = find_jointree_node_for_rel(lfirst(l), relid); |
4927 | 0 | if (jtnode) |
4928 | 0 | return jtnode; |
4929 | 0 | } |
4930 | 0 | } |
4931 | 0 | else if (IsA(jtnode, JoinExpr)) |
4932 | 0 | { |
4933 | 0 | JoinExpr *j = (JoinExpr *) jtnode; |
4934 | |
|
4935 | 0 | if (relid == j->rtindex) |
4936 | 0 | return jtnode; |
4937 | 0 | jtnode = find_jointree_node_for_rel(j->larg, relid); |
4938 | 0 | if (jtnode) |
4939 | 0 | return jtnode; |
4940 | 0 | jtnode = find_jointree_node_for_rel(j->rarg, relid); |
4941 | 0 | if (jtnode) |
4942 | 0 | return jtnode; |
4943 | 0 | } |
4944 | 0 | else |
4945 | 0 | elog(ERROR, "unrecognized node type: %d", |
4946 | 0 | (int) nodeTag(jtnode)); |
4947 | 0 | return NULL; |
4948 | 0 | } |
4949 | | |
4950 | | /* |
4951 | | * get_nullingrels: collect info about which outer joins null which relations |
4952 | | * |
4953 | | * The result struct contains, for each leaf relation used in the query, |
4954 | | * the set of relids of outer joins that potentially null that rel. |
4955 | | */ |
4956 | | static nullingrel_info * |
4957 | | get_nullingrels(Query *parse) |
4958 | 0 | { |
4959 | 0 | nullingrel_info *result = palloc_object(nullingrel_info); |
4960 | |
|
4961 | 0 | result->rtlength = list_length(parse->rtable); |
4962 | 0 | result->nullingrels = palloc0_array(Relids, result->rtlength + 1); |
4963 | 0 | get_nullingrels_recurse((Node *) parse->jointree, NULL, result); |
4964 | 0 | return result; |
4965 | 0 | } |
4966 | | |
4967 | | /* |
4968 | | * Recursive guts of get_nullingrels(). |
4969 | | * |
4970 | | * Note: at any recursion level, the passed-down upper_nullingrels must be |
4971 | | * treated as a constant, but it can be stored directly into *info |
4972 | | * if we're at leaf level. Upper recursion levels do not free their mutated |
4973 | | * copies of the nullingrels, because those are probably referenced by |
4974 | | * at least one leaf rel. |
4975 | | */ |
4976 | | static void |
4977 | | get_nullingrels_recurse(Node *jtnode, Relids upper_nullingrels, |
4978 | | nullingrel_info *info) |
4979 | 0 | { |
4980 | 0 | if (jtnode == NULL) |
4981 | 0 | return; |
4982 | 0 | if (IsA(jtnode, RangeTblRef)) |
4983 | 0 | { |
4984 | 0 | int varno = ((RangeTblRef *) jtnode)->rtindex; |
4985 | |
|
4986 | 0 | Assert(varno > 0 && varno <= info->rtlength); |
4987 | 0 | info->nullingrels[varno] = upper_nullingrels; |
4988 | 0 | } |
4989 | 0 | else if (IsA(jtnode, FromExpr)) |
4990 | 0 | { |
4991 | 0 | FromExpr *f = (FromExpr *) jtnode; |
4992 | 0 | ListCell *l; |
4993 | |
|
4994 | 0 | foreach(l, f->fromlist) |
4995 | 0 | { |
4996 | 0 | get_nullingrels_recurse(lfirst(l), upper_nullingrels, info); |
4997 | 0 | } |
4998 | 0 | } |
4999 | 0 | else if (IsA(jtnode, JoinExpr)) |
5000 | 0 | { |
5001 | 0 | JoinExpr *j = (JoinExpr *) jtnode; |
5002 | 0 | Relids local_nullingrels; |
5003 | |
|
5004 | 0 | switch (j->jointype) |
5005 | 0 | { |
5006 | 0 | case JOIN_INNER: |
5007 | 0 | get_nullingrels_recurse(j->larg, upper_nullingrels, info); |
5008 | 0 | get_nullingrels_recurse(j->rarg, upper_nullingrels, info); |
5009 | 0 | break; |
5010 | 0 | case JOIN_LEFT: |
5011 | 0 | case JOIN_SEMI: |
5012 | 0 | case JOIN_ANTI: |
5013 | 0 | local_nullingrels = bms_add_member(bms_copy(upper_nullingrels), |
5014 | 0 | j->rtindex); |
5015 | 0 | get_nullingrels_recurse(j->larg, upper_nullingrels, info); |
5016 | 0 | get_nullingrels_recurse(j->rarg, local_nullingrels, info); |
5017 | 0 | break; |
5018 | 0 | case JOIN_FULL: |
5019 | 0 | local_nullingrels = bms_add_member(bms_copy(upper_nullingrels), |
5020 | 0 | j->rtindex); |
5021 | 0 | get_nullingrels_recurse(j->larg, local_nullingrels, info); |
5022 | 0 | get_nullingrels_recurse(j->rarg, local_nullingrels, info); |
5023 | 0 | break; |
5024 | 0 | case JOIN_RIGHT: |
5025 | 0 | local_nullingrels = bms_add_member(bms_copy(upper_nullingrels), |
5026 | 0 | j->rtindex); |
5027 | 0 | get_nullingrels_recurse(j->larg, local_nullingrels, info); |
5028 | 0 | get_nullingrels_recurse(j->rarg, upper_nullingrels, info); |
5029 | 0 | break; |
5030 | 0 | default: |
5031 | 0 | elog(ERROR, "unrecognized join type: %d", |
5032 | 0 | (int) j->jointype); |
5033 | 0 | break; |
5034 | 0 | } |
5035 | 0 | } |
5036 | 0 | else |
5037 | 0 | elog(ERROR, "unrecognized node type: %d", |
5038 | 0 | (int) nodeTag(jtnode)); |
5039 | 0 | } |