Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * prepunion.c
4 : * Routines to plan set-operation queries. The filename is a leftover
5 : * from a time when only UNIONs were implemented.
6 : *
7 : * There are two code paths in the planner for set-operation queries.
8 : * If a subquery consists entirely of simple UNION ALL operations, it
9 : * is converted into an "append relation". Otherwise, it is handled
10 : * by the general code in this module (plan_set_operations and its
11 : * subroutines). There is some support code here for the append-relation
12 : * case, but most of the heavy lifting for that is done elsewhere,
13 : * notably in prepjointree.c and allpaths.c.
14 : *
15 : * There is also some code here to support planning of queries that use
16 : * inheritance (SELECT FROM foo*). Inheritance trees are converted into
17 : * append relations, and thenceforth share code with the UNION ALL case.
18 : *
19 : *
20 : * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
21 : * Portions Copyright (c) 1994, Regents of the University of California
22 : *
23 : *
24 : * IDENTIFICATION
25 : * src/backend/optimizer/prep/prepunion.c
26 : *
27 : *-------------------------------------------------------------------------
28 : */
29 : #include "postgres.h"
30 :
31 : #include <limits.h>
32 :
33 : #include "access/heapam.h"
34 : #include "access/htup_details.h"
35 : #include "access/sysattr.h"
36 : #include "catalog/partition.h"
37 : #include "catalog/pg_inherits_fn.h"
38 : #include "catalog/pg_type.h"
39 : #include "miscadmin.h"
40 : #include "nodes/makefuncs.h"
41 : #include "nodes/nodeFuncs.h"
42 : #include "optimizer/cost.h"
43 : #include "optimizer/pathnode.h"
44 : #include "optimizer/paths.h"
45 : #include "optimizer/planmain.h"
46 : #include "optimizer/planner.h"
47 : #include "optimizer/prep.h"
48 : #include "optimizer/tlist.h"
49 : #include "parser/parse_coerce.h"
50 : #include "parser/parsetree.h"
51 : #include "utils/lsyscache.h"
52 : #include "utils/rel.h"
53 : #include "utils/selfuncs.h"
54 :
55 :
56 : typedef struct
57 : {
58 : PlannerInfo *root;
59 : int nappinfos;
60 : AppendRelInfo **appinfos;
61 : } adjust_appendrel_attrs_context;
62 :
63 : static Path *recurse_set_operations(Node *setOp, PlannerInfo *root,
64 : List *colTypes, List *colCollations,
65 : bool junkOK,
66 : int flag, List *refnames_tlist,
67 : List **pTargetList,
68 : double *pNumGroups);
69 : static Path *generate_recursion_path(SetOperationStmt *setOp,
70 : PlannerInfo *root,
71 : List *refnames_tlist,
72 : List **pTargetList);
73 : static Path *generate_union_path(SetOperationStmt *op, PlannerInfo *root,
74 : List *refnames_tlist,
75 : List **pTargetList,
76 : double *pNumGroups);
77 : static Path *generate_nonunion_path(SetOperationStmt *op, PlannerInfo *root,
78 : List *refnames_tlist,
79 : List **pTargetList,
80 : double *pNumGroups);
81 : static List *recurse_union_children(Node *setOp, PlannerInfo *root,
82 : SetOperationStmt *top_union,
83 : List *refnames_tlist,
84 : List **tlist_list);
85 : static Path *make_union_unique(SetOperationStmt *op, Path *path, List *tlist,
86 : PlannerInfo *root);
87 : static bool choose_hashed_setop(PlannerInfo *root, List *groupClauses,
88 : Path *input_path,
89 : double dNumGroups, double dNumOutputRows,
90 : const char *construct);
91 : static List *generate_setop_tlist(List *colTypes, List *colCollations,
92 : int flag,
93 : Index varno,
94 : bool hack_constants,
95 : List *input_tlist,
96 : List *refnames_tlist);
97 : static List *generate_append_tlist(List *colTypes, List *colCollations,
98 : bool flag,
99 : List *input_tlists,
100 : List *refnames_tlist);
101 : static List *generate_setop_grouplist(SetOperationStmt *op, List *targetlist);
102 : static void expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte,
103 : Index rti);
104 : static void expand_partitioned_rtentry(PlannerInfo *root,
105 : RangeTblEntry *parentrte,
106 : Index parentRTindex, Relation parentrel,
107 : PlanRowMark *parentrc, PartitionDesc partdesc,
108 : LOCKMODE lockmode,
109 : bool *has_child, List **appinfos,
110 : List **partitioned_child_rels);
111 : static void expand_single_inheritance_child(PlannerInfo *root,
112 : RangeTblEntry *parentrte,
113 : Index parentRTindex, Relation parentrel,
114 : PlanRowMark *parentrc, Relation childrel,
115 : bool *has_child, List **appinfos,
116 : List **partitioned_child_rels);
117 : static void make_inh_translation_list(Relation oldrelation,
118 : Relation newrelation,
119 : Index newvarno,
120 : List **translated_vars);
121 : static Bitmapset *translate_col_privs(const Bitmapset *parent_privs,
122 : List *translated_vars);
123 : static Node *adjust_appendrel_attrs_mutator(Node *node,
124 : adjust_appendrel_attrs_context *context);
125 : static Relids adjust_child_relids(Relids relids, int nappinfos,
126 : AppendRelInfo **appinfos);
127 : static List *adjust_inherited_tlist(List *tlist,
128 : AppendRelInfo *context);
129 :
130 :
131 : /*
132 : * plan_set_operations
133 : *
134 : * Plans the queries for a tree of set operations (UNION/INTERSECT/EXCEPT)
135 : *
136 : * This routine only deals with the setOperations tree of the given query.
137 : * Any top-level ORDER BY requested in root->parse->sortClause will be handled
138 : * when we return to grouping_planner; likewise for LIMIT.
139 : *
140 : * What we return is an "upperrel" RelOptInfo containing at least one Path
141 : * that implements the set-operation tree. In addition, root->processed_tlist
142 : * receives a targetlist representing the output of the topmost setop node.
143 : */
144 : RelOptInfo *
145 127 : plan_set_operations(PlannerInfo *root)
146 : {
147 127 : Query *parse = root->parse;
148 127 : SetOperationStmt *topop = castNode(SetOperationStmt, parse->setOperations);
149 : Node *node;
150 : RangeTblEntry *leftmostRTE;
151 : Query *leftmostQuery;
152 : RelOptInfo *setop_rel;
153 : Path *path;
154 : List *top_tlist;
155 :
156 127 : Assert(topop);
157 :
158 : /* check for unsupported stuff */
159 127 : Assert(parse->jointree->fromlist == NIL);
160 127 : Assert(parse->jointree->quals == NULL);
161 127 : Assert(parse->groupClause == NIL);
162 127 : Assert(parse->havingQual == NULL);
163 127 : Assert(parse->windowClause == NIL);
164 127 : Assert(parse->distinctClause == NIL);
165 :
166 : /*
167 : * We'll need to build RelOptInfos for each of the leaf subqueries, which
168 : * are RTE_SUBQUERY rangetable entries in this Query. Prepare the index
169 : * arrays for that.
170 : */
171 127 : setup_simple_rel_arrays(root);
172 :
173 : /*
174 : * Find the leftmost component Query. We need to use its column names for
175 : * all generated tlists (else SELECT INTO won't work right).
176 : */
177 127 : node = topop->larg;
178 269 : while (node && IsA(node, SetOperationStmt))
179 15 : node = ((SetOperationStmt *) node)->larg;
180 127 : Assert(node && IsA(node, RangeTblRef));
181 127 : leftmostRTE = root->simple_rte_array[((RangeTblRef *) node)->rtindex];
182 127 : leftmostQuery = leftmostRTE->subquery;
183 127 : Assert(leftmostQuery != NULL);
184 :
185 : /*
186 : * We return our results in the (SETOP, NULL) upperrel. For the moment,
187 : * this is also the parent rel of all Paths in the setop tree; we may well
188 : * change that in future.
189 : */
190 127 : setop_rel = fetch_upper_rel(root, UPPERREL_SETOP, NULL);
191 :
192 : /*
193 : * We don't currently worry about setting setop_rel's consider_parallel
194 : * flag, nor about allowing FDWs to contribute paths to it.
195 : */
196 :
197 : /*
198 : * If the topmost node is a recursive union, it needs special processing.
199 : */
200 127 : if (root->hasRecursion)
201 : {
202 40 : path = generate_recursion_path(topop, root,
203 : leftmostQuery->targetList,
204 : &top_tlist);
205 : }
206 : else
207 : {
208 : /*
209 : * Recurse on setOperations tree to generate paths for set ops. The
210 : * final output path should have just the column types shown as the
211 : * output from the top-level node, plus possibly resjunk working
212 : * columns (we can rely on upper-level nodes to deal with that).
213 : */
214 87 : path = recurse_set_operations((Node *) topop, root,
215 : topop->colTypes, topop->colCollations,
216 : true, -1,
217 : leftmostQuery->targetList,
218 : &top_tlist,
219 : NULL);
220 : }
221 :
222 : /* Must return the built tlist into root->processed_tlist. */
223 127 : root->processed_tlist = top_tlist;
224 :
225 : /* Add only the final path to the SETOP upperrel. */
226 127 : add_path(setop_rel, path);
227 :
228 : /* Let extensions possibly add some more paths */
229 127 : if (create_upper_paths_hook)
230 0 : (*create_upper_paths_hook) (root, UPPERREL_SETOP,
231 : NULL, setop_rel);
232 :
233 : /* Select cheapest path */
234 127 : set_cheapest(setop_rel);
235 :
236 127 : return setop_rel;
237 : }
238 :
239 : /*
240 : * recurse_set_operations
241 : * Recursively handle one step in a tree of set operations
242 : *
243 : * colTypes: OID list of set-op's result column datatypes
244 : * colCollations: OID list of set-op's result column collations
245 : * junkOK: if true, child resjunk columns may be left in the result
246 : * flag: if >= 0, add a resjunk output column indicating value of flag
247 : * refnames_tlist: targetlist to take column names from
248 : *
249 : * Returns a path for the subtree, as well as these output parameters:
250 : * *pTargetList: receives the fully-fledged tlist for the subtree's top plan
251 : * *pNumGroups: if not NULL, we estimate the number of distinct groups
252 : * in the result, and store it there
253 : *
254 : * The pTargetList output parameter is mostly redundant with the pathtarget
255 : * of the returned path, but for the moment we need it because much of the
256 : * logic in this file depends on flag columns being marked resjunk. Pending
257 : * a redesign of how that works, this is the easy way out.
258 : *
259 : * We don't have to care about typmods here: the only allowed difference
260 : * between set-op input and output typmods is input is a specific typmod
261 : * and output is -1, and that does not require a coercion.
262 : */
263 : static Path *
264 371 : recurse_set_operations(Node *setOp, PlannerInfo *root,
265 : List *colTypes, List *colCollations,
266 : bool junkOK,
267 : int flag, List *refnames_tlist,
268 : List **pTargetList,
269 : double *pNumGroups)
270 : {
271 371 : if (IsA(setOp, RangeTblRef))
272 : {
273 272 : RangeTblRef *rtr = (RangeTblRef *) setOp;
274 272 : RangeTblEntry *rte = root->simple_rte_array[rtr->rtindex];
275 272 : Query *subquery = rte->subquery;
276 : RelOptInfo *rel;
277 : PlannerInfo *subroot;
278 : RelOptInfo *final_rel;
279 : Path *subpath;
280 : Path *path;
281 : List *tlist;
282 :
283 272 : Assert(subquery != NULL);
284 :
285 : /*
286 : * We need to build a RelOptInfo for each leaf subquery. This isn't
287 : * used for much here, but it carries the subroot data structures
288 : * forward to setrefs.c processing.
289 : */
290 272 : rel = build_simple_rel(root, rtr->rtindex, NULL);
291 :
292 : /* plan_params should not be in use in current query level */
293 272 : Assert(root->plan_params == NIL);
294 :
295 : /* Generate a subroot and Paths for the subquery */
296 272 : subroot = rel->subroot = subquery_planner(root->glob, subquery,
297 : root,
298 : false,
299 : root->tuple_fraction);
300 :
301 : /*
302 : * It should not be possible for the primitive query to contain any
303 : * cross-references to other primitive queries in the setop tree.
304 : */
305 272 : if (root->plan_params)
306 0 : elog(ERROR, "unexpected outer reference in set operation subquery");
307 :
308 : /*
309 : * Mark rel with estimated output rows, width, etc. Note that we have
310 : * to do this before generating outer-query paths, else
311 : * cost_subqueryscan is not happy.
312 : */
313 272 : set_subquery_size_estimates(root, rel);
314 :
315 : /*
316 : * For the moment, we consider only a single Path for the subquery.
317 : * This should change soon (make it look more like
318 : * set_subquery_pathlist).
319 : */
320 272 : final_rel = fetch_upper_rel(subroot, UPPERREL_FINAL, NULL);
321 272 : subpath = get_cheapest_fractional_path(final_rel,
322 : root->tuple_fraction);
323 :
324 : /*
325 : * Stick a SubqueryScanPath atop that.
326 : *
327 : * We don't bother to determine the subquery's output ordering since
328 : * it won't be reflected in the set-op result anyhow; so just label
329 : * the SubqueryScanPath with nil pathkeys. (XXX that should change
330 : * soon too, likely.)
331 : */
332 272 : path = (Path *) create_subqueryscan_path(root, rel, subpath,
333 : NIL, NULL);
334 :
335 : /*
336 : * Figure out the appropriate target list, and update the
337 : * SubqueryScanPath with the PathTarget form of that.
338 : */
339 544 : tlist = generate_setop_tlist(colTypes, colCollations,
340 : flag,
341 272 : rtr->rtindex,
342 : true,
343 : subroot->processed_tlist,
344 : refnames_tlist);
345 :
346 272 : path = apply_projection_to_path(root, rel, path,
347 : create_pathtarget(root, tlist));
348 :
349 : /* Return the fully-fledged tlist to caller, too */
350 272 : *pTargetList = tlist;
351 :
352 : /*
353 : * Estimate number of groups if caller wants it. If the subquery used
354 : * grouping or aggregation, its output is probably mostly unique
355 : * anyway; otherwise do statistical estimation.
356 : *
357 : * XXX you don't really want to know about this: we do the estimation
358 : * using the subquery's original targetlist expressions, not the
359 : * subroot->processed_tlist which might seem more appropriate. The
360 : * reason is that if the subquery is itself a setop, it may return a
361 : * processed_tlist containing "varno 0" Vars generated by
362 : * generate_append_tlist, and those would confuse estimate_num_groups
363 : * mightily. We ought to get rid of the "varno 0" hack, but that
364 : * requires a redesign of the parsetree representation of setops, so
365 : * that there can be an RTE corresponding to each setop's output.
366 : */
367 272 : if (pNumGroups)
368 : {
369 136 : if (subquery->groupClause || subquery->groupingSets ||
370 134 : subquery->distinctClause ||
371 132 : subroot->hasHavingQual || subquery->hasAggs)
372 2 : *pNumGroups = subpath->rows;
373 : else
374 66 : *pNumGroups = estimate_num_groups(subroot,
375 : get_tlist_exprs(subquery->targetList, false),
376 : subpath->rows,
377 : NULL);
378 : }
379 :
380 272 : return (Path *) path;
381 : }
382 99 : else if (IsA(setOp, SetOperationStmt))
383 : {
384 99 : SetOperationStmt *op = (SetOperationStmt *) setOp;
385 : Path *path;
386 :
387 : /* UNIONs are much different from INTERSECT/EXCEPT */
388 99 : if (op->op == SETOP_UNION)
389 62 : path = generate_union_path(op, root,
390 : refnames_tlist,
391 : pTargetList,
392 : pNumGroups);
393 : else
394 37 : path = generate_nonunion_path(op, root,
395 : refnames_tlist,
396 : pTargetList,
397 : pNumGroups);
398 :
399 : /*
400 : * If necessary, add a Result node to project the caller-requested
401 : * output columns.
402 : *
403 : * XXX you don't really want to know about this: setrefs.c will apply
404 : * fix_upper_expr() to the Result node's tlist. This would fail if the
405 : * Vars generated by generate_setop_tlist() were not exactly equal()
406 : * to the corresponding tlist entries of the subplan. However, since
407 : * the subplan was generated by generate_union_plan() or
408 : * generate_nonunion_plan(), and hence its tlist was generated by
409 : * generate_append_tlist(), this will work. We just tell
410 : * generate_setop_tlist() to use varno 0.
411 : */
412 192 : if (flag >= 0 ||
413 183 : !tlist_same_datatypes(*pTargetList, colTypes, junkOK) ||
414 90 : !tlist_same_collations(*pTargetList, colCollations, junkOK))
415 : {
416 9 : *pTargetList = generate_setop_tlist(colTypes, colCollations,
417 : flag,
418 : 0,
419 : false,
420 : *pTargetList,
421 : refnames_tlist);
422 9 : path = apply_projection_to_path(root,
423 : path->parent,
424 : path,
425 : create_pathtarget(root,
426 : *pTargetList));
427 : }
428 99 : return path;
429 : }
430 : else
431 : {
432 0 : elog(ERROR, "unrecognized node type: %d",
433 : (int) nodeTag(setOp));
434 : *pTargetList = NIL;
435 : return NULL; /* keep compiler quiet */
436 : }
437 : }
438 :
439 : /*
440 : * Generate path for a recursive UNION node
441 : */
442 : static Path *
443 40 : generate_recursion_path(SetOperationStmt *setOp, PlannerInfo *root,
444 : List *refnames_tlist,
445 : List **pTargetList)
446 : {
447 40 : RelOptInfo *result_rel = fetch_upper_rel(root, UPPERREL_SETOP, NULL);
448 : Path *path;
449 : Path *lpath;
450 : Path *rpath;
451 : List *lpath_tlist;
452 : List *rpath_tlist;
453 : List *tlist;
454 : List *groupList;
455 : double dNumGroups;
456 :
457 : /* Parser should have rejected other cases */
458 40 : if (setOp->op != SETOP_UNION)
459 0 : elog(ERROR, "only UNION queries can be recursive");
460 : /* Worktable ID should be assigned */
461 40 : Assert(root->wt_param_id >= 0);
462 :
463 : /*
464 : * Unlike a regular UNION node, process the left and right inputs
465 : * separately without any intention of combining them into one Append.
466 : */
467 40 : lpath = recurse_set_operations(setOp->larg, root,
468 : setOp->colTypes, setOp->colCollations,
469 : false, -1,
470 : refnames_tlist,
471 : &lpath_tlist,
472 : NULL);
473 : /* The right path will want to look at the left one ... */
474 40 : root->non_recursive_path = lpath;
475 40 : rpath = recurse_set_operations(setOp->rarg, root,
476 : setOp->colTypes, setOp->colCollations,
477 : false, -1,
478 : refnames_tlist,
479 : &rpath_tlist,
480 : NULL);
481 40 : root->non_recursive_path = NULL;
482 :
483 : /*
484 : * Generate tlist for RecursiveUnion path node --- same as in Append cases
485 : */
486 40 : tlist = generate_append_tlist(setOp->colTypes, setOp->colCollations, false,
487 : list_make2(lpath_tlist, rpath_tlist),
488 : refnames_tlist);
489 :
490 40 : *pTargetList = tlist;
491 :
492 : /*
493 : * If UNION, identify the grouping operators
494 : */
495 40 : if (setOp->all)
496 : {
497 36 : groupList = NIL;
498 36 : dNumGroups = 0;
499 : }
500 : else
501 : {
502 : /* Identify the grouping semantics */
503 4 : groupList = generate_setop_grouplist(setOp, tlist);
504 :
505 : /* We only support hashing here */
506 4 : if (!grouping_is_hashable(groupList))
507 0 : ereport(ERROR,
508 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
509 : errmsg("could not implement recursive UNION"),
510 : errdetail("All column datatypes must be hashable.")));
511 :
512 : /*
513 : * For the moment, take the number of distinct groups as equal to the
514 : * total input size, ie, the worst case.
515 : */
516 4 : dNumGroups = lpath->rows + rpath->rows * 10;
517 : }
518 :
519 : /*
520 : * And make the path node.
521 : */
522 40 : path = (Path *) create_recursiveunion_path(root,
523 : result_rel,
524 : lpath,
525 : rpath,
526 : create_pathtarget(root, tlist),
527 : groupList,
528 : root->wt_param_id,
529 : dNumGroups);
530 :
531 40 : return path;
532 : }
533 :
534 : /*
535 : * Generate path for a UNION or UNION ALL node
536 : */
537 : static Path *
538 62 : generate_union_path(SetOperationStmt *op, PlannerInfo *root,
539 : List *refnames_tlist,
540 : List **pTargetList,
541 : double *pNumGroups)
542 : {
543 62 : RelOptInfo *result_rel = fetch_upper_rel(root, UPPERREL_SETOP, NULL);
544 62 : double save_fraction = root->tuple_fraction;
545 : List *pathlist;
546 : List *child_tlists1;
547 : List *child_tlists2;
548 : List *tlist_list;
549 : List *tlist;
550 : Path *path;
551 :
552 : /*
553 : * If plain UNION, tell children to fetch all tuples.
554 : *
555 : * Note: in UNION ALL, we pass the top-level tuple_fraction unmodified to
556 : * each arm of the UNION ALL. One could make a case for reducing the
557 : * tuple fraction for later arms (discounting by the expected size of the
558 : * earlier arms' results) but it seems not worth the trouble. The normal
559 : * case where tuple_fraction isn't already zero is a LIMIT at top level,
560 : * and passing it down as-is is usually enough to get the desired result
561 : * of preferring fast-start plans.
562 : */
563 62 : if (!op->all)
564 47 : root->tuple_fraction = 0.0;
565 :
566 : /*
567 : * If any of my children are identical UNION nodes (same op, all-flag, and
568 : * colTypes) then they can be merged into this node so that we generate
569 : * only one Append and unique-ification for the lot. Recurse to find such
570 : * nodes and compute their children's paths.
571 : */
572 62 : pathlist = list_concat(recurse_union_children(op->larg, root,
573 : op, refnames_tlist,
574 : &child_tlists1),
575 : recurse_union_children(op->rarg, root,
576 : op, refnames_tlist,
577 : &child_tlists2));
578 62 : tlist_list = list_concat(child_tlists1, child_tlists2);
579 :
580 : /*
581 : * Generate tlist for Append plan node.
582 : *
583 : * The tlist for an Append plan isn't important as far as the Append is
584 : * concerned, but we must make it look real anyway for the benefit of the
585 : * next plan level up.
586 : */
587 62 : tlist = generate_append_tlist(op->colTypes, op->colCollations, false,
588 : tlist_list, refnames_tlist);
589 :
590 62 : *pTargetList = tlist;
591 :
592 : /*
593 : * Append the child results together.
594 : */
595 62 : path = (Path *) create_append_path(result_rel, pathlist, NULL, 0, NIL);
596 :
597 : /* We have to manually jam the right tlist into the path; ick */
598 62 : path->pathtarget = create_pathtarget(root, tlist);
599 :
600 : /*
601 : * For UNION ALL, we just need the Append path. For UNION, need to add
602 : * node(s) to remove duplicates.
603 : */
604 62 : if (!op->all)
605 47 : path = make_union_unique(op, path, tlist, root);
606 :
607 : /*
608 : * Estimate number of groups if caller wants it. For now we just assume
609 : * the output is unique --- this is certainly true for the UNION case, and
610 : * we want worst-case estimates anyway.
611 : */
612 62 : if (pNumGroups)
613 5 : *pNumGroups = path->rows;
614 :
615 : /* Undo effects of possibly forcing tuple_fraction to 0 */
616 62 : root->tuple_fraction = save_fraction;
617 :
618 62 : return path;
619 : }
620 :
621 : /*
622 : * Generate path for an INTERSECT, INTERSECT ALL, EXCEPT, or EXCEPT ALL node
623 : */
624 : static Path *
625 37 : generate_nonunion_path(SetOperationStmt *op, PlannerInfo *root,
626 : List *refnames_tlist,
627 : List **pTargetList,
628 : double *pNumGroups)
629 : {
630 37 : RelOptInfo *result_rel = fetch_upper_rel(root, UPPERREL_SETOP, NULL);
631 37 : double save_fraction = root->tuple_fraction;
632 : Path *lpath,
633 : *rpath,
634 : *path;
635 : List *lpath_tlist,
636 : *rpath_tlist,
637 : *tlist_list,
638 : *tlist,
639 : *groupList,
640 : *pathlist;
641 : double dLeftGroups,
642 : dRightGroups,
643 : dNumGroups,
644 : dNumOutputRows;
645 : bool use_hash;
646 : SetOpCmd cmd;
647 : int firstFlag;
648 :
649 : /*
650 : * Tell children to fetch all tuples.
651 : */
652 37 : root->tuple_fraction = 0.0;
653 :
654 : /* Recurse on children, ensuring their outputs are marked */
655 37 : lpath = recurse_set_operations(op->larg, root,
656 : op->colTypes, op->colCollations,
657 : false, 0,
658 : refnames_tlist,
659 : &lpath_tlist,
660 : &dLeftGroups);
661 37 : rpath = recurse_set_operations(op->rarg, root,
662 : op->colTypes, op->colCollations,
663 : false, 1,
664 : refnames_tlist,
665 : &rpath_tlist,
666 : &dRightGroups);
667 :
668 : /* Undo effects of forcing tuple_fraction to 0 */
669 37 : root->tuple_fraction = save_fraction;
670 :
671 : /*
672 : * For EXCEPT, we must put the left input first. For INTERSECT, either
673 : * order should give the same results, and we prefer to put the smaller
674 : * input first in order to minimize the size of the hash table in the
675 : * hashing case. "Smaller" means the one with the fewer groups.
676 : */
677 37 : if (op->op == SETOP_EXCEPT || dLeftGroups <= dRightGroups)
678 : {
679 32 : pathlist = list_make2(lpath, rpath);
680 32 : tlist_list = list_make2(lpath_tlist, rpath_tlist);
681 32 : firstFlag = 0;
682 : }
683 : else
684 : {
685 5 : pathlist = list_make2(rpath, lpath);
686 5 : tlist_list = list_make2(rpath_tlist, lpath_tlist);
687 5 : firstFlag = 1;
688 : }
689 :
690 : /*
691 : * Generate tlist for Append plan node.
692 : *
693 : * The tlist for an Append plan isn't important as far as the Append is
694 : * concerned, but we must make it look real anyway for the benefit of the
695 : * next plan level up. In fact, it has to be real enough that the flag
696 : * column is shown as a variable not a constant, else setrefs.c will get
697 : * confused.
698 : */
699 37 : tlist = generate_append_tlist(op->colTypes, op->colCollations, true,
700 : tlist_list, refnames_tlist);
701 :
702 37 : *pTargetList = tlist;
703 :
704 : /*
705 : * Append the child results together.
706 : */
707 37 : path = (Path *) create_append_path(result_rel, pathlist, NULL, 0, NIL);
708 :
709 : /* We have to manually jam the right tlist into the path; ick */
710 37 : path->pathtarget = create_pathtarget(root, tlist);
711 :
712 : /* Identify the grouping semantics */
713 37 : groupList = generate_setop_grouplist(op, tlist);
714 :
715 : /* punt if nothing to group on (can this happen?) */
716 37 : if (groupList == NIL)
717 0 : return path;
718 :
719 : /*
720 : * Estimate number of distinct groups that we'll need hashtable entries
721 : * for; this is the size of the left-hand input for EXCEPT, or the smaller
722 : * input for INTERSECT. Also estimate the number of eventual output rows.
723 : * In non-ALL cases, we estimate each group produces one output row; in
724 : * ALL cases use the relevant relation size. These are worst-case
725 : * estimates, of course, but we need to be conservative.
726 : */
727 37 : if (op->op == SETOP_EXCEPT)
728 : {
729 22 : dNumGroups = dLeftGroups;
730 22 : dNumOutputRows = op->all ? lpath->rows : dNumGroups;
731 : }
732 : else
733 : {
734 15 : dNumGroups = Min(dLeftGroups, dRightGroups);
735 15 : dNumOutputRows = op->all ? Min(lpath->rows, rpath->rows) : dNumGroups;
736 : }
737 :
738 : /*
739 : * Decide whether to hash or sort, and add a sort node if needed.
740 : */
741 37 : use_hash = choose_hashed_setop(root, groupList, path,
742 : dNumGroups, dNumOutputRows,
743 37 : (op->op == SETOP_INTERSECT) ? "INTERSECT" : "EXCEPT");
744 :
745 37 : if (!use_hash)
746 4 : path = (Path *) create_sort_path(root,
747 : result_rel,
748 : path,
749 : make_pathkeys_for_sortclauses(root,
750 : groupList,
751 : tlist),
752 : -1.0);
753 :
754 : /*
755 : * Finally, add a SetOp path node to generate the correct output.
756 : */
757 37 : switch (op->op)
758 : {
759 : case SETOP_INTERSECT:
760 15 : cmd = op->all ? SETOPCMD_INTERSECT_ALL : SETOPCMD_INTERSECT;
761 15 : break;
762 : case SETOP_EXCEPT:
763 22 : cmd = op->all ? SETOPCMD_EXCEPT_ALL : SETOPCMD_EXCEPT;
764 22 : break;
765 : default:
766 0 : elog(ERROR, "unrecognized set op: %d", (int) op->op);
767 : cmd = SETOPCMD_INTERSECT; /* keep compiler quiet */
768 : break;
769 : }
770 74 : path = (Path *) create_setop_path(root,
771 : result_rel,
772 : path,
773 : cmd,
774 : use_hash ? SETOP_HASHED : SETOP_SORTED,
775 : groupList,
776 37 : list_length(op->colTypes) + 1,
777 : use_hash ? firstFlag : -1,
778 : dNumGroups,
779 : dNumOutputRows);
780 :
781 37 : if (pNumGroups)
782 1 : *pNumGroups = dNumGroups;
783 :
784 37 : return path;
785 : }
786 :
787 : /*
788 : * Pull up children of a UNION node that are identically-propertied UNIONs.
789 : *
790 : * NOTE: we can also pull a UNION ALL up into a UNION, since the distinct
791 : * output rows will be lost anyway.
792 : *
793 : * NOTE: currently, we ignore collations while determining if a child has
794 : * the same properties. This is semantically sound only so long as all
795 : * collations have the same notion of equality. It is valid from an
796 : * implementation standpoint because we don't care about the ordering of
797 : * a UNION child's result: UNION ALL results are always unordered, and
798 : * generate_union_path will force a fresh sort if the top level is a UNION.
799 : */
800 : static List *
801 136 : recurse_union_children(Node *setOp, PlannerInfo *root,
802 : SetOperationStmt *top_union,
803 : List *refnames_tlist,
804 : List **tlist_list)
805 : {
806 : List *result;
807 : List *child_tlist;
808 :
809 136 : if (IsA(setOp, SetOperationStmt))
810 : {
811 11 : SetOperationStmt *op = (SetOperationStmt *) setOp;
812 :
813 21 : if (op->op == top_union->op &&
814 21 : (op->all == top_union->all || op->all) &&
815 8 : equal(op->colTypes, top_union->colTypes))
816 : {
817 : /* Same UNION, so fold children into parent's subpath list */
818 : List *child_tlists1;
819 : List *child_tlists2;
820 :
821 6 : result = list_concat(recurse_union_children(op->larg, root,
822 : top_union,
823 : refnames_tlist,
824 : &child_tlists1),
825 : recurse_union_children(op->rarg, root,
826 : top_union,
827 : refnames_tlist,
828 : &child_tlists2));
829 6 : *tlist_list = list_concat(child_tlists1, child_tlists2);
830 6 : return result;
831 : }
832 : }
833 :
834 : /*
835 : * Not same, so plan this child separately.
836 : *
837 : * Note we disallow any resjunk columns in child results. This is
838 : * necessary since the Append node that implements the union won't do any
839 : * projection, and upper levels will get confused if some of our output
840 : * tuples have junk and some don't. This case only arises when we have an
841 : * EXCEPT or INTERSECT as child, else there won't be resjunk anyway.
842 : */
843 130 : result = list_make1(recurse_set_operations(setOp, root,
844 : top_union->colTypes,
845 : top_union->colCollations,
846 : false, -1,
847 : refnames_tlist,
848 : &child_tlist,
849 : NULL));
850 130 : *tlist_list = list_make1(child_tlist);
851 130 : return result;
852 : }
853 :
854 : /*
855 : * Add nodes to the given path tree to unique-ify the result of a UNION.
856 : */
857 : static Path *
858 47 : make_union_unique(SetOperationStmt *op, Path *path, List *tlist,
859 : PlannerInfo *root)
860 : {
861 47 : RelOptInfo *result_rel = fetch_upper_rel(root, UPPERREL_SETOP, NULL);
862 : List *groupList;
863 : double dNumGroups;
864 :
865 : /* Identify the grouping semantics */
866 47 : groupList = generate_setop_grouplist(op, tlist);
867 :
868 : /* punt if nothing to group on (can this happen?) */
869 47 : if (groupList == NIL)
870 0 : return path;
871 :
872 : /*
873 : * XXX for the moment, take the number of distinct groups as equal to the
874 : * total input size, ie, the worst case. This is too conservative, but we
875 : * don't want to risk having the hashtable overrun memory; also, it's not
876 : * clear how to get a decent estimate of the true size. One should note
877 : * as well the propensity of novices to write UNION rather than UNION ALL
878 : * even when they don't expect any duplicates...
879 : */
880 47 : dNumGroups = path->rows;
881 :
882 : /* Decide whether to hash or sort */
883 47 : if (choose_hashed_setop(root, groupList, path,
884 : dNumGroups, dNumGroups,
885 : "UNION"))
886 : {
887 : /* Hashed aggregate plan --- no sort needed */
888 25 : path = (Path *) create_agg_path(root,
889 : result_rel,
890 : path,
891 : create_pathtarget(root, tlist),
892 : AGG_HASHED,
893 : AGGSPLIT_SIMPLE,
894 : groupList,
895 : NIL,
896 : NULL,
897 : dNumGroups);
898 : }
899 : else
900 : {
901 : /* Sort and Unique */
902 22 : path = (Path *) create_sort_path(root,
903 : result_rel,
904 : path,
905 : make_pathkeys_for_sortclauses(root,
906 : groupList,
907 : tlist),
908 : -1.0);
909 : /* We have to manually jam the right tlist into the path; ick */
910 22 : path->pathtarget = create_pathtarget(root, tlist);
911 22 : path = (Path *) create_upper_unique_path(root,
912 : result_rel,
913 : path,
914 22 : list_length(path->pathkeys),
915 : dNumGroups);
916 : }
917 :
918 47 : return path;
919 : }
920 :
921 : /*
922 : * choose_hashed_setop - should we use hashing for a set operation?
923 : */
924 : static bool
925 84 : choose_hashed_setop(PlannerInfo *root, List *groupClauses,
926 : Path *input_path,
927 : double dNumGroups, double dNumOutputRows,
928 : const char *construct)
929 : {
930 84 : int numGroupCols = list_length(groupClauses);
931 : bool can_sort;
932 : bool can_hash;
933 : Size hashentrysize;
934 : Path hashed_p;
935 : Path sorted_p;
936 : double tuple_fraction;
937 :
938 : /* Check whether the operators support sorting or hashing */
939 84 : can_sort = grouping_is_sortable(groupClauses);
940 84 : can_hash = grouping_is_hashable(groupClauses);
941 84 : if (can_hash && can_sort)
942 : {
943 : /* we have a meaningful choice to make, continue ... */
944 : }
945 1 : else if (can_hash)
946 1 : return true;
947 0 : else if (can_sort)
948 0 : return false;
949 : else
950 0 : ereport(ERROR,
951 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
952 : /* translator: %s is UNION, INTERSECT, or EXCEPT */
953 : errmsg("could not implement %s", construct),
954 : errdetail("Some of the datatypes only support hashing, while others only support sorting.")));
955 :
956 : /* Prefer sorting when enable_hashagg is off */
957 83 : if (!enable_hashagg)
958 4 : return false;
959 :
960 : /*
961 : * Don't do it if it doesn't look like the hashtable will fit into
962 : * work_mem.
963 : */
964 79 : hashentrysize = MAXALIGN(input_path->pathtarget->width) + MAXALIGN(SizeofMinimalTupleHeader);
965 :
966 79 : if (hashentrysize * dNumGroups > work_mem * 1024L)
967 0 : return false;
968 :
969 : /*
970 : * See if the estimated cost is no more than doing it the other way.
971 : *
972 : * We need to consider input_plan + hashagg versus input_plan + sort +
973 : * group. Note that the actual result plan might involve a SetOp or
974 : * Unique node, not Agg or Group, but the cost estimates for Agg and Group
975 : * should be close enough for our purposes here.
976 : *
977 : * These path variables are dummies that just hold cost fields; we don't
978 : * make actual Paths for these steps.
979 : */
980 79 : cost_agg(&hashed_p, root, AGG_HASHED, NULL,
981 : numGroupCols, dNumGroups,
982 : input_path->startup_cost, input_path->total_cost,
983 : input_path->rows);
984 :
985 : /*
986 : * Now for the sorted case. Note that the input is *always* unsorted,
987 : * since it was made by appending unrelated sub-relations together.
988 : */
989 79 : sorted_p.startup_cost = input_path->startup_cost;
990 79 : sorted_p.total_cost = input_path->total_cost;
991 : /* XXX cost_sort doesn't actually look at pathkeys, so just pass NIL */
992 158 : cost_sort(&sorted_p, root, NIL, sorted_p.total_cost,
993 79 : input_path->rows, input_path->pathtarget->width,
994 : 0.0, work_mem, -1.0);
995 79 : cost_group(&sorted_p, root, numGroupCols, dNumGroups,
996 : sorted_p.startup_cost, sorted_p.total_cost,
997 : input_path->rows);
998 :
999 : /*
1000 : * Now make the decision using the top-level tuple fraction. First we
1001 : * have to convert an absolute count (LIMIT) into fractional form.
1002 : */
1003 79 : tuple_fraction = root->tuple_fraction;
1004 79 : if (tuple_fraction >= 1.0)
1005 0 : tuple_fraction /= dNumOutputRows;
1006 :
1007 79 : if (compare_fractional_path_costs(&hashed_p, &sorted_p,
1008 : tuple_fraction) < 0)
1009 : {
1010 : /* Hashed is cheaper, so use it */
1011 57 : return true;
1012 : }
1013 22 : return false;
1014 : }
1015 :
1016 : /*
1017 : * Generate targetlist for a set-operation plan node
1018 : *
1019 : * colTypes: OID list of set-op's result column datatypes
1020 : * colCollations: OID list of set-op's result column collations
1021 : * flag: -1 if no flag column needed, 0 or 1 to create a const flag column
1022 : * varno: varno to use in generated Vars
1023 : * hack_constants: true to copy up constants (see comments in code)
1024 : * input_tlist: targetlist of this node's input node
1025 : * refnames_tlist: targetlist to take column names from
1026 : */
1027 : static List *
1028 281 : generate_setop_tlist(List *colTypes, List *colCollations,
1029 : int flag,
1030 : Index varno,
1031 : bool hack_constants,
1032 : List *input_tlist,
1033 : List *refnames_tlist)
1034 : {
1035 281 : List *tlist = NIL;
1036 281 : int resno = 1;
1037 : ListCell *ctlc,
1038 : *cclc,
1039 : *itlc,
1040 : *rtlc;
1041 : TargetEntry *tle;
1042 : Node *expr;
1043 :
1044 : /* there's no forfour() so we must chase one list manually */
1045 281 : rtlc = list_head(refnames_tlist);
1046 704 : forthree(ctlc, colTypes, cclc, colCollations, itlc, input_tlist)
1047 : {
1048 423 : Oid colType = lfirst_oid(ctlc);
1049 423 : Oid colColl = lfirst_oid(cclc);
1050 423 : TargetEntry *inputtle = (TargetEntry *) lfirst(itlc);
1051 423 : TargetEntry *reftle = (TargetEntry *) lfirst(rtlc);
1052 :
1053 423 : rtlc = lnext(rtlc);
1054 :
1055 423 : Assert(inputtle->resno == resno);
1056 423 : Assert(reftle->resno == resno);
1057 423 : Assert(!inputtle->resjunk);
1058 423 : Assert(!reftle->resjunk);
1059 :
1060 : /*
1061 : * Generate columns referencing input columns and having appropriate
1062 : * data types and column names. Insert datatype coercions where
1063 : * necessary.
1064 : *
1065 : * HACK: constants in the input's targetlist are copied up as-is
1066 : * rather than being referenced as subquery outputs. This is mainly
1067 : * to ensure that when we try to coerce them to the output column's
1068 : * datatype, the right things happen for UNKNOWN constants. But do
1069 : * this only at the first level of subquery-scan plans; we don't want
1070 : * phony constants appearing in the output tlists of upper-level
1071 : * nodes!
1072 : */
1073 423 : if (hack_constants && inputtle->expr && IsA(inputtle->expr, Const))
1074 153 : expr = (Node *) inputtle->expr;
1075 : else
1076 1080 : expr = (Node *) makeVar(varno,
1077 270 : inputtle->resno,
1078 270 : exprType((Node *) inputtle->expr),
1079 270 : exprTypmod((Node *) inputtle->expr),
1080 270 : exprCollation((Node *) inputtle->expr),
1081 : 0);
1082 :
1083 423 : if (exprType(expr) != colType)
1084 : {
1085 : /*
1086 : * Note: it's not really cool to be applying coerce_to_common_type
1087 : * here; one notable point is that assign_expr_collations never
1088 : * gets run on any generated nodes. For the moment that's not a
1089 : * problem because we force the correct exposed collation below.
1090 : * It would likely be best to make the parser generate the correct
1091 : * output tlist for every set-op to begin with, though.
1092 : */
1093 24 : expr = coerce_to_common_type(NULL, /* no UNKNOWNs here */
1094 : expr,
1095 : colType,
1096 : "UNION/INTERSECT/EXCEPT");
1097 : }
1098 :
1099 : /*
1100 : * Ensure the tlist entry's exposed collation matches the set-op. This
1101 : * is necessary because plan_set_operations() reports the result
1102 : * ordering as a list of SortGroupClauses, which don't carry collation
1103 : * themselves but just refer to tlist entries. If we don't show the
1104 : * right collation then planner.c might do the wrong thing in
1105 : * higher-level queries.
1106 : *
1107 : * Note we use RelabelType, not CollateExpr, since this expression
1108 : * will reach the executor without any further processing.
1109 : */
1110 423 : if (exprCollation(expr) != colColl)
1111 : {
1112 4 : expr = (Node *) makeRelabelType((Expr *) expr,
1113 : exprType(expr),
1114 : exprTypmod(expr),
1115 : colColl,
1116 : COERCE_IMPLICIT_CAST);
1117 : }
1118 :
1119 846 : tle = makeTargetEntry((Expr *) expr,
1120 423 : (AttrNumber) resno++,
1121 423 : pstrdup(reftle->resname),
1122 : false);
1123 :
1124 : /*
1125 : * By convention, all non-resjunk columns in a setop tree have
1126 : * ressortgroupref equal to their resno. In some cases the ref isn't
1127 : * needed, but this is a cleaner way than modifying the tlist later.
1128 : */
1129 423 : tle->ressortgroupref = tle->resno;
1130 :
1131 423 : tlist = lappend(tlist, tle);
1132 : }
1133 :
1134 281 : if (flag >= 0)
1135 : {
1136 : /* Add a resjunk flag column */
1137 : /* flag value is the given constant */
1138 74 : expr = (Node *) makeConst(INT4OID,
1139 : -1,
1140 : InvalidOid,
1141 : sizeof(int32),
1142 : Int32GetDatum(flag),
1143 : false,
1144 : true);
1145 148 : tle = makeTargetEntry((Expr *) expr,
1146 74 : (AttrNumber) resno++,
1147 : pstrdup("flag"),
1148 : true);
1149 74 : tlist = lappend(tlist, tle);
1150 : }
1151 :
1152 281 : return tlist;
1153 : }
1154 :
1155 : /*
1156 : * Generate targetlist for a set-operation Append node
1157 : *
1158 : * colTypes: OID list of set-op's result column datatypes
1159 : * colCollations: OID list of set-op's result column collations
1160 : * flag: true to create a flag column copied up from subplans
1161 : * input_tlists: list of tlists for sub-plans of the Append
1162 : * refnames_tlist: targetlist to take column names from
1163 : *
1164 : * The entries in the Append's targetlist should always be simple Vars;
1165 : * we just have to make sure they have the right datatypes/typmods/collations.
1166 : * The Vars are always generated with varno 0.
1167 : *
1168 : * XXX a problem with the varno-zero approach is that set_pathtarget_cost_width
1169 : * cannot figure out a realistic width for the tlist we make here. But we
1170 : * ought to refactor this code to produce a PathTarget directly, anyway.
1171 : */
1172 : static List *
1173 139 : generate_append_tlist(List *colTypes, List *colCollations,
1174 : bool flag,
1175 : List *input_tlists,
1176 : List *refnames_tlist)
1177 : {
1178 139 : List *tlist = NIL;
1179 139 : int resno = 1;
1180 : ListCell *curColType;
1181 : ListCell *curColCollation;
1182 : ListCell *ref_tl_item;
1183 : int colindex;
1184 : TargetEntry *tle;
1185 : Node *expr;
1186 : ListCell *tlistl;
1187 : int32 *colTypmods;
1188 :
1189 : /*
1190 : * First extract typmods to use.
1191 : *
1192 : * If the inputs all agree on type and typmod of a particular column, use
1193 : * that typmod; else use -1.
1194 : */
1195 139 : colTypmods = (int32 *) palloc(list_length(colTypes) * sizeof(int32));
1196 :
1197 423 : foreach(tlistl, input_tlists)
1198 : {
1199 284 : List *subtlist = (List *) lfirst(tlistl);
1200 : ListCell *subtlistl;
1201 :
1202 284 : curColType = list_head(colTypes);
1203 284 : colindex = 0;
1204 786 : foreach(subtlistl, subtlist)
1205 : {
1206 502 : TargetEntry *subtle = (TargetEntry *) lfirst(subtlistl);
1207 :
1208 502 : if (subtle->resjunk)
1209 74 : continue;
1210 428 : Assert(curColType != NULL);
1211 428 : if (exprType((Node *) subtle->expr) == lfirst_oid(curColType))
1212 : {
1213 : /* If first subplan, copy the typmod; else compare */
1214 428 : int32 subtypmod = exprTypmod((Node *) subtle->expr);
1215 :
1216 428 : if (tlistl == list_head(input_tlists))
1217 211 : colTypmods[colindex] = subtypmod;
1218 217 : else if (subtypmod != colTypmods[colindex])
1219 2 : colTypmods[colindex] = -1;
1220 : }
1221 : else
1222 : {
1223 : /* types disagree, so force typmod to -1 */
1224 0 : colTypmods[colindex] = -1;
1225 : }
1226 428 : curColType = lnext(curColType);
1227 428 : colindex++;
1228 : }
1229 284 : Assert(curColType == NULL);
1230 : }
1231 :
1232 : /*
1233 : * Now we can build the tlist for the Append.
1234 : */
1235 139 : colindex = 0;
1236 350 : forthree(curColType, colTypes, curColCollation, colCollations,
1237 : ref_tl_item, refnames_tlist)
1238 : {
1239 211 : Oid colType = lfirst_oid(curColType);
1240 211 : int32 colTypmod = colTypmods[colindex++];
1241 211 : Oid colColl = lfirst_oid(curColCollation);
1242 211 : TargetEntry *reftle = (TargetEntry *) lfirst(ref_tl_item);
1243 :
1244 211 : Assert(reftle->resno == resno);
1245 211 : Assert(!reftle->resjunk);
1246 211 : expr = (Node *) makeVar(0,
1247 : resno,
1248 : colType,
1249 : colTypmod,
1250 : colColl,
1251 : 0);
1252 422 : tle = makeTargetEntry((Expr *) expr,
1253 211 : (AttrNumber) resno++,
1254 211 : pstrdup(reftle->resname),
1255 : false);
1256 :
1257 : /*
1258 : * By convention, all non-resjunk columns in a setop tree have
1259 : * ressortgroupref equal to their resno. In some cases the ref isn't
1260 : * needed, but this is a cleaner way than modifying the tlist later.
1261 : */
1262 211 : tle->ressortgroupref = tle->resno;
1263 :
1264 211 : tlist = lappend(tlist, tle);
1265 : }
1266 :
1267 139 : if (flag)
1268 : {
1269 : /* Add a resjunk flag column */
1270 : /* flag value is shown as copied up from subplan */
1271 37 : expr = (Node *) makeVar(0,
1272 : resno,
1273 : INT4OID,
1274 : -1,
1275 : InvalidOid,
1276 : 0);
1277 74 : tle = makeTargetEntry((Expr *) expr,
1278 37 : (AttrNumber) resno++,
1279 : pstrdup("flag"),
1280 : true);
1281 37 : tlist = lappend(tlist, tle);
1282 : }
1283 :
1284 139 : pfree(colTypmods);
1285 :
1286 139 : return tlist;
1287 : }
1288 :
1289 : /*
1290 : * generate_setop_grouplist
1291 : * Build a SortGroupClause list defining the sort/grouping properties
1292 : * of the setop's output columns.
1293 : *
1294 : * Parse analysis already determined the properties and built a suitable
1295 : * list, except that the entries do not have sortgrouprefs set because
1296 : * the parser output representation doesn't include a tlist for each
1297 : * setop. So what we need to do here is copy that list and install
1298 : * proper sortgrouprefs into it (copying those from the targetlist).
1299 : */
1300 : static List *
1301 88 : generate_setop_grouplist(SetOperationStmt *op, List *targetlist)
1302 : {
1303 88 : List *grouplist = copyObject(op->groupClauses);
1304 : ListCell *lg;
1305 : ListCell *lt;
1306 :
1307 88 : lg = list_head(grouplist);
1308 248 : foreach(lt, targetlist)
1309 : {
1310 160 : TargetEntry *tle = (TargetEntry *) lfirst(lt);
1311 : SortGroupClause *sgc;
1312 :
1313 160 : if (tle->resjunk)
1314 : {
1315 : /* resjunk columns should not have sortgrouprefs */
1316 37 : Assert(tle->ressortgroupref == 0);
1317 37 : continue; /* ignore resjunk columns */
1318 : }
1319 :
1320 : /* non-resjunk columns should have sortgroupref = resno */
1321 123 : Assert(tle->ressortgroupref == tle->resno);
1322 :
1323 : /* non-resjunk columns should have grouping clauses */
1324 123 : Assert(lg != NULL);
1325 123 : sgc = (SortGroupClause *) lfirst(lg);
1326 123 : lg = lnext(lg);
1327 123 : Assert(sgc->tleSortGroupRef == 0);
1328 :
1329 123 : sgc->tleSortGroupRef = tle->ressortgroupref;
1330 : }
1331 88 : Assert(lg == NULL);
1332 88 : return grouplist;
1333 : }
1334 :
1335 :
1336 : /*
1337 : * expand_inherited_tables
1338 : * Expand each rangetable entry that represents an inheritance set
1339 : * into an "append relation". At the conclusion of this process,
1340 : * the "inh" flag is set in all and only those RTEs that are append
1341 : * relation parents.
1342 : */
1343 : void
1344 25426 : expand_inherited_tables(PlannerInfo *root)
1345 : {
1346 : Index nrtes;
1347 : Index rti;
1348 : ListCell *rl;
1349 :
1350 : /*
1351 : * expand_inherited_rtentry may add RTEs to parse->rtable; there is no
1352 : * need to scan them since they can't have inh=true. So just scan as far
1353 : * as the original end of the rtable list.
1354 : */
1355 25426 : nrtes = list_length(root->parse->rtable);
1356 25426 : rl = list_head(root->parse->rtable);
1357 54321 : for (rti = 1; rti <= nrtes; rti++)
1358 : {
1359 28895 : RangeTblEntry *rte = (RangeTblEntry *) lfirst(rl);
1360 :
1361 28895 : expand_inherited_rtentry(root, rte, rti);
1362 28895 : rl = lnext(rl);
1363 : }
1364 25426 : }
1365 :
1366 : /*
1367 : * expand_inherited_rtentry
1368 : * Check whether a rangetable entry represents an inheritance set.
1369 : * If so, add entries for all the child tables to the query's
1370 : * rangetable, and build AppendRelInfo nodes for all the child tables
1371 : * and add them to root->append_rel_list. If not, clear the entry's
1372 : * "inh" flag to prevent later code from looking for AppendRelInfos.
1373 : *
1374 : * Note that the original RTE is considered to represent the whole
1375 : * inheritance set. The first of the generated RTEs is an RTE for the same
1376 : * table, but with inh = false, to represent the parent table in its role
1377 : * as a simple member of the inheritance set.
1378 : *
1379 : * A childless table is never considered to be an inheritance set. For
1380 : * regular inheritance, a parent RTE must always have at least two associated
1381 : * AppendRelInfos: one corresponding to the parent table as a simple member of
1382 : * inheritance set and one or more corresponding to the actual children.
1383 : * Since a partitioned table is not scanned, it might have only one associated
1384 : * AppendRelInfo.
1385 : */
1386 : static void
1387 28895 : expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
1388 : {
1389 28895 : Query *parse = root->parse;
1390 : Oid parentOID;
1391 : PlanRowMark *oldrc;
1392 : Relation oldrelation;
1393 : LOCKMODE lockmode;
1394 : List *inhOIDs;
1395 : List *appinfos;
1396 : ListCell *l;
1397 : bool has_child;
1398 : PartitionedChildRelInfo *pcinfo;
1399 28895 : List *partitioned_child_rels = NIL;
1400 :
1401 : /* Does RT entry allow inheritance? */
1402 28895 : if (!rte->inh)
1403 42382 : return;
1404 : /* Ignore any already-expanded UNION ALL nodes */
1405 15065 : if (rte->rtekind != RTE_RELATION)
1406 : {
1407 273 : Assert(rte->rtekind == RTE_SUBQUERY);
1408 273 : return;
1409 : }
1410 : /* Fast path for common case of childless table */
1411 14792 : parentOID = rte->relid;
1412 14792 : if (!has_subclass(parentOID))
1413 : {
1414 : /* Clear flag before returning */
1415 14422 : rte->inh = false;
1416 14422 : return;
1417 : }
1418 :
1419 : /*
1420 : * The rewriter should already have obtained an appropriate lock on each
1421 : * relation named in the query. However, for each child relation we add
1422 : * to the query, we must obtain an appropriate lock, because this will be
1423 : * the first use of those relations in the parse/rewrite/plan pipeline.
1424 : *
1425 : * If the parent relation is the query's result relation, then we need
1426 : * RowExclusiveLock. Otherwise, if it's accessed FOR UPDATE/SHARE, we
1427 : * need RowShareLock; otherwise AccessShareLock. We can't just grab
1428 : * AccessShareLock because then the executor would be trying to upgrade
1429 : * the lock, leading to possible deadlocks. (This code should match the
1430 : * parser and rewriter.)
1431 : */
1432 370 : oldrc = get_plan_rowmark(root->rowMarks, rti);
1433 370 : if (rti == parse->resultRelation)
1434 77 : lockmode = RowExclusiveLock;
1435 293 : else if (oldrc && RowMarkRequiresRowShareLock(oldrc->markType))
1436 8 : lockmode = RowShareLock;
1437 : else
1438 285 : lockmode = AccessShareLock;
1439 :
1440 : /* Scan for all members of inheritance set, acquire needed locks */
1441 370 : inhOIDs = find_all_inheritors(parentOID, lockmode, NULL);
1442 :
1443 : /*
1444 : * Check that there's at least one descendant, else treat as no-child
1445 : * case. This could happen despite above has_subclass() check, if table
1446 : * once had a child but no longer does.
1447 : */
1448 370 : if (list_length(inhOIDs) < 2)
1449 : {
1450 : /* Clear flag before returning */
1451 27 : rte->inh = false;
1452 27 : return;
1453 : }
1454 :
1455 : /*
1456 : * If parent relation is selected FOR UPDATE/SHARE, we need to mark its
1457 : * PlanRowMark as isParent = true, and generate a new PlanRowMark for each
1458 : * child.
1459 : */
1460 343 : if (oldrc)
1461 16 : oldrc->isParent = true;
1462 :
1463 : /*
1464 : * Must open the parent relation to examine its tupdesc. We need not lock
1465 : * it; we assume the rewriter already did.
1466 : */
1467 343 : oldrelation = heap_open(parentOID, NoLock);
1468 :
1469 : /* Scan the inheritance set and expand it */
1470 343 : appinfos = NIL;
1471 343 : has_child = false;
1472 343 : if (RelationGetPartitionDesc(oldrelation) != NULL)
1473 : {
1474 : /*
1475 : * If this table has partitions, recursively expand them in the order
1476 : * in which they appear in the PartitionDesc. But first, expand the
1477 : * parent itself.
1478 : */
1479 66 : expand_single_inheritance_child(root, rte, rti, oldrelation, oldrc,
1480 : oldrelation,
1481 : &has_child, &appinfos,
1482 : &partitioned_child_rels);
1483 66 : expand_partitioned_rtentry(root, rte, rti, oldrelation, oldrc,
1484 : RelationGetPartitionDesc(oldrelation),
1485 : lockmode,
1486 : &has_child, &appinfos,
1487 : &partitioned_child_rels);
1488 : }
1489 : else
1490 : {
1491 : /*
1492 : * This table has no partitions. Expand any plain inheritance
1493 : * children in the order the OIDs were returned by
1494 : * find_all_inheritors.
1495 : */
1496 1085 : foreach(l, inhOIDs)
1497 : {
1498 808 : Oid childOID = lfirst_oid(l);
1499 : Relation newrelation;
1500 :
1501 : /* Open rel if needed; we already have required locks */
1502 808 : if (childOID != parentOID)
1503 531 : newrelation = heap_open(childOID, NoLock);
1504 : else
1505 277 : newrelation = oldrelation;
1506 :
1507 : /*
1508 : * It is possible that the parent table has children that are temp
1509 : * tables of other backends. We cannot safely access such tables
1510 : * (because of buffering issues), and the best thing to do seems
1511 : * to be to silently ignore them.
1512 : */
1513 808 : if (childOID != parentOID && RELATION_IS_OTHER_TEMP(newrelation))
1514 : {
1515 0 : heap_close(newrelation, lockmode);
1516 0 : continue;
1517 : }
1518 :
1519 808 : expand_single_inheritance_child(root, rte, rti, oldrelation, oldrc,
1520 : newrelation,
1521 : &has_child, &appinfos,
1522 : &partitioned_child_rels);
1523 :
1524 : /* Close child relations, but keep locks */
1525 808 : if (childOID != parentOID)
1526 531 : heap_close(newrelation, NoLock);
1527 : }
1528 : }
1529 :
1530 343 : heap_close(oldrelation, NoLock);
1531 :
1532 : /*
1533 : * If all the children were temp tables or a partitioned parent did not
1534 : * have any leaf partitions, pretend it's a non-inheritance situation; we
1535 : * don't need Append node in that case. The duplicate RTE we added for
1536 : * the parent table is harmless, so we don't bother to get rid of it;
1537 : * ditto for the useless PlanRowMark node.
1538 : */
1539 343 : if (!has_child)
1540 : {
1541 : /* Clear flag before returning */
1542 0 : rte->inh = false;
1543 0 : return;
1544 : }
1545 :
1546 : /*
1547 : * We keep a list of objects in root, each of which maps a partitioned
1548 : * parent RT index to the list of RT indexes of its partitioned child
1549 : * tables. When creating an Append or a ModifyTable path for the parent,
1550 : * we copy the child RT index list verbatim to the path so that it could
1551 : * be carried over to the executor so that the latter could identify the
1552 : * partitioned child tables.
1553 : */
1554 343 : if (partitioned_child_rels != NIL)
1555 : {
1556 66 : pcinfo = makeNode(PartitionedChildRelInfo);
1557 :
1558 66 : Assert(rte->relkind == RELKIND_PARTITIONED_TABLE);
1559 66 : pcinfo->parent_relid = rti;
1560 66 : pcinfo->child_rels = partitioned_child_rels;
1561 66 : root->pcinfo_list = lappend(root->pcinfo_list, pcinfo);
1562 : }
1563 :
1564 : /* Otherwise, OK to add to root->append_rel_list */
1565 343 : root->append_rel_list = list_concat(root->append_rel_list, appinfos);
1566 : }
1567 :
1568 : static void
1569 105 : expand_partitioned_rtentry(PlannerInfo *root, RangeTblEntry *parentrte,
1570 : Index parentRTindex, Relation parentrel,
1571 : PlanRowMark *parentrc, PartitionDesc partdesc,
1572 : LOCKMODE lockmode,
1573 : bool *has_child, List **appinfos,
1574 : List **partitioned_child_rels)
1575 : {
1576 : int i;
1577 :
1578 105 : check_stack_depth();
1579 :
1580 413 : for (i = 0; i < partdesc->nparts; i++)
1581 : {
1582 308 : Oid childOID = partdesc->oids[i];
1583 : Relation childrel;
1584 :
1585 : /* Open rel; we already have required locks */
1586 308 : childrel = heap_open(childOID, NoLock);
1587 :
1588 : /* As in expand_inherited_rtentry, skip non-local temp tables */
1589 308 : if (RELATION_IS_OTHER_TEMP(childrel))
1590 : {
1591 0 : heap_close(childrel, lockmode);
1592 0 : continue;
1593 : }
1594 :
1595 308 : expand_single_inheritance_child(root, parentrte, parentRTindex,
1596 : parentrel, parentrc, childrel,
1597 : has_child, appinfos,
1598 : partitioned_child_rels);
1599 :
1600 : /* If this child is itself partitioned, recurse */
1601 308 : if (childrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
1602 39 : expand_partitioned_rtentry(root, parentrte, parentRTindex,
1603 : parentrel, parentrc,
1604 : RelationGetPartitionDesc(childrel),
1605 : lockmode,
1606 : has_child, appinfos,
1607 : partitioned_child_rels);
1608 :
1609 : /* Close child relation, but keep locks */
1610 308 : heap_close(childrel, NoLock);
1611 : }
1612 105 : }
1613 :
1614 : /*
1615 : * expand_single_inheritance_child
1616 : * Expand a single inheritance child, if needed.
1617 : *
1618 : * If this is a temp table of another backend, we'll return without doing
1619 : * anything at all. Otherwise, we'll set "has_child" to true, build a
1620 : * RangeTblEntry and either a PartitionedChildRelInfo or AppendRelInfo as
1621 : * appropriate, plus maybe a PlanRowMark.
1622 : */
1623 : static void
1624 1182 : expand_single_inheritance_child(PlannerInfo *root, RangeTblEntry *parentrte,
1625 : Index parentRTindex, Relation parentrel,
1626 : PlanRowMark *parentrc, Relation childrel,
1627 : bool *has_child, List **appinfos,
1628 : List **partitioned_child_rels)
1629 : {
1630 1182 : Query *parse = root->parse;
1631 1182 : Oid parentOID = RelationGetRelid(parentrel);
1632 1182 : Oid childOID = RelationGetRelid(childrel);
1633 : RangeTblEntry *childrte;
1634 : Index childRTindex;
1635 : AppendRelInfo *appinfo;
1636 :
1637 : /*
1638 : * Build an RTE for the child, and attach to query's rangetable list. We
1639 : * copy most fields of the parent's RTE, but replace relation OID and
1640 : * relkind, and set inh = false. Also, set requiredPerms to zero since
1641 : * all required permissions checks are done on the original RTE. Likewise,
1642 : * set the child's securityQuals to empty, because we only want to apply
1643 : * the parent's RLS conditions regardless of what RLS properties
1644 : * individual children may have. (This is an intentional choice to make
1645 : * inherited RLS work like regular permissions checks.) The parent
1646 : * securityQuals will be propagated to children along with other base
1647 : * restriction clauses, so we don't need to do it here.
1648 : */
1649 1182 : childrte = copyObject(parentrte);
1650 1182 : childrte->relid = childOID;
1651 1182 : childrte->relkind = childrel->rd_rel->relkind;
1652 1182 : childrte->inh = false;
1653 1182 : childrte->requiredPerms = 0;
1654 1182 : childrte->securityQuals = NIL;
1655 1182 : parse->rtable = lappend(parse->rtable, childrte);
1656 1182 : childRTindex = list_length(parse->rtable);
1657 :
1658 : /*
1659 : * Build an AppendRelInfo for this parent and child, unless the child is a
1660 : * partitioned table.
1661 : */
1662 1182 : if (childrte->relkind != RELKIND_PARTITIONED_TABLE)
1663 : {
1664 : /* Remember if we saw a real child. */
1665 1077 : if (childOID != parentOID)
1666 800 : *has_child = true;
1667 :
1668 1077 : appinfo = makeNode(AppendRelInfo);
1669 1077 : appinfo->parent_relid = parentRTindex;
1670 1077 : appinfo->child_relid = childRTindex;
1671 1077 : appinfo->parent_reltype = parentrel->rd_rel->reltype;
1672 1077 : appinfo->child_reltype = childrel->rd_rel->reltype;
1673 1077 : make_inh_translation_list(parentrel, childrel, childRTindex,
1674 : &appinfo->translated_vars);
1675 1077 : appinfo->parent_reloid = parentOID;
1676 1077 : *appinfos = lappend(*appinfos, appinfo);
1677 :
1678 : /*
1679 : * Translate the column permissions bitmaps to the child's attnums (we
1680 : * have to build the translated_vars list before we can do this). But
1681 : * if this is the parent table, leave copyObject's result alone.
1682 : *
1683 : * Note: we need to do this even though the executor won't run any
1684 : * permissions checks on the child RTE. The insertedCols/updatedCols
1685 : * bitmaps may be examined for trigger-firing purposes.
1686 : */
1687 1077 : if (childOID != parentOID)
1688 : {
1689 800 : childrte->selectedCols = translate_col_privs(parentrte->selectedCols,
1690 : appinfo->translated_vars);
1691 800 : childrte->insertedCols = translate_col_privs(parentrte->insertedCols,
1692 : appinfo->translated_vars);
1693 800 : childrte->updatedCols = translate_col_privs(parentrte->updatedCols,
1694 : appinfo->translated_vars);
1695 : }
1696 : }
1697 : else
1698 105 : *partitioned_child_rels = lappend_int(*partitioned_child_rels,
1699 : childRTindex);
1700 :
1701 : /*
1702 : * Build a PlanRowMark if parent is marked FOR UPDATE/SHARE.
1703 : */
1704 1182 : if (parentrc)
1705 : {
1706 42 : PlanRowMark *childrc = makeNode(PlanRowMark);
1707 :
1708 42 : childrc->rti = childRTindex;
1709 42 : childrc->prti = parentRTindex;
1710 42 : childrc->rowmarkId = parentrc->rowmarkId;
1711 : /* Reselect rowmark type, because relkind might not match parent */
1712 42 : childrc->markType = select_rowmark_type(childrte, parentrc->strength);
1713 42 : childrc->allMarkTypes = (1 << childrc->markType);
1714 42 : childrc->strength = parentrc->strength;
1715 42 : childrc->waitPolicy = parentrc->waitPolicy;
1716 :
1717 : /*
1718 : * We mark RowMarks for partitioned child tables as parent RowMarks so
1719 : * that the executor ignores them (except their existence means that
1720 : * the child tables be locked using appropriate mode).
1721 : */
1722 42 : childrc->isParent = (childrte->relkind == RELKIND_PARTITIONED_TABLE);
1723 :
1724 : /* Include child's rowmark type in parent's allMarkTypes */
1725 42 : parentrc->allMarkTypes |= childrc->allMarkTypes;
1726 :
1727 42 : root->rowMarks = lappend(root->rowMarks, childrc);
1728 : }
1729 1182 : }
1730 :
1731 : /*
1732 : * make_inh_translation_list
1733 : * Build the list of translations from parent Vars to child Vars for
1734 : * an inheritance child.
1735 : *
1736 : * For paranoia's sake, we match type/collation as well as attribute name.
1737 : */
1738 : static void
1739 1077 : make_inh_translation_list(Relation oldrelation, Relation newrelation,
1740 : Index newvarno,
1741 : List **translated_vars)
1742 : {
1743 1077 : List *vars = NIL;
1744 1077 : TupleDesc old_tupdesc = RelationGetDescr(oldrelation);
1745 1077 : TupleDesc new_tupdesc = RelationGetDescr(newrelation);
1746 1077 : int oldnatts = old_tupdesc->natts;
1747 1077 : int newnatts = new_tupdesc->natts;
1748 : int old_attno;
1749 :
1750 3667 : for (old_attno = 0; old_attno < oldnatts; old_attno++)
1751 : {
1752 : Form_pg_attribute att;
1753 : char *attname;
1754 : Oid atttypid;
1755 : int32 atttypmod;
1756 : Oid attcollation;
1757 : int new_attno;
1758 :
1759 2590 : att = TupleDescAttr(old_tupdesc, old_attno);
1760 2590 : if (att->attisdropped)
1761 : {
1762 : /* Just put NULL into this list entry */
1763 129 : vars = lappend(vars, NULL);
1764 129 : continue;
1765 : }
1766 2461 : attname = NameStr(att->attname);
1767 2461 : atttypid = att->atttypid;
1768 2461 : atttypmod = att->atttypmod;
1769 2461 : attcollation = att->attcollation;
1770 :
1771 : /*
1772 : * When we are generating the "translation list" for the parent table
1773 : * of an inheritance set, no need to search for matches.
1774 : */
1775 2461 : if (oldrelation == newrelation)
1776 : {
1777 617 : vars = lappend(vars, makeVar(newvarno,
1778 617 : (AttrNumber) (old_attno + 1),
1779 : atttypid,
1780 : atttypmod,
1781 : attcollation,
1782 : 0));
1783 617 : continue;
1784 : }
1785 :
1786 : /*
1787 : * Otherwise we have to search for the matching column by name.
1788 : * There's no guarantee it'll have the same column position, because
1789 : * of cases like ALTER TABLE ADD COLUMN and multiple inheritance.
1790 : * However, in simple cases it will be the same column number, so try
1791 : * that before we go groveling through all the columns.
1792 : *
1793 : * Note: the test for (att = ...) != NULL cannot fail, it's just a
1794 : * notational device to include the assignment into the if-clause.
1795 : */
1796 3688 : if (old_attno < newnatts &&
1797 3688 : (att = TupleDescAttr(new_tupdesc, old_attno)) != NULL &&
1798 5416 : !att->attisdropped && att->attinhcount != 0 &&
1799 1736 : strcmp(attname, NameStr(att->attname)) == 0)
1800 1622 : new_attno = old_attno;
1801 : else
1802 : {
1803 652 : for (new_attno = 0; new_attno < newnatts; new_attno++)
1804 : {
1805 652 : att = TupleDescAttr(new_tupdesc, new_attno);
1806 1170 : if (!att->attisdropped && att->attinhcount != 0 &&
1807 518 : strcmp(attname, NameStr(att->attname)) == 0)
1808 222 : break;
1809 : }
1810 222 : if (new_attno >= newnatts)
1811 0 : elog(ERROR, "could not find inherited attribute \"%s\" of relation \"%s\"",
1812 : attname, RelationGetRelationName(newrelation));
1813 : }
1814 :
1815 : /* Found it, check type and collation match */
1816 1844 : if (atttypid != att->atttypid || atttypmod != att->atttypmod)
1817 0 : elog(ERROR, "attribute \"%s\" of relation \"%s\" does not match parent's type",
1818 : attname, RelationGetRelationName(newrelation));
1819 1844 : if (attcollation != att->attcollation)
1820 0 : elog(ERROR, "attribute \"%s\" of relation \"%s\" does not match parent's collation",
1821 : attname, RelationGetRelationName(newrelation));
1822 :
1823 1844 : vars = lappend(vars, makeVar(newvarno,
1824 1844 : (AttrNumber) (new_attno + 1),
1825 : atttypid,
1826 : atttypmod,
1827 : attcollation,
1828 : 0));
1829 : }
1830 :
1831 1077 : *translated_vars = vars;
1832 1077 : }
1833 :
1834 : /*
1835 : * translate_col_privs
1836 : * Translate a bitmapset representing per-column privileges from the
1837 : * parent rel's attribute numbering to the child's.
1838 : *
1839 : * The only surprise here is that we don't translate a parent whole-row
1840 : * reference into a child whole-row reference. That would mean requiring
1841 : * permissions on all child columns, which is overly strict, since the
1842 : * query is really only going to reference the inherited columns. Instead
1843 : * we set the per-column bits for all inherited columns.
1844 : */
1845 : static Bitmapset *
1846 2400 : translate_col_privs(const Bitmapset *parent_privs,
1847 : List *translated_vars)
1848 : {
1849 2400 : Bitmapset *child_privs = NULL;
1850 : bool whole_row;
1851 : int attno;
1852 : ListCell *lc;
1853 :
1854 : /* System attributes have the same numbers in all tables */
1855 19200 : for (attno = FirstLowInvalidHeapAttributeNumber + 1; attno < 0; attno++)
1856 : {
1857 16800 : if (bms_is_member(attno - FirstLowInvalidHeapAttributeNumber,
1858 : parent_privs))
1859 83 : child_privs = bms_add_member(child_privs,
1860 : attno - FirstLowInvalidHeapAttributeNumber);
1861 : }
1862 :
1863 : /* Check if parent has whole-row reference */
1864 2400 : whole_row = bms_is_member(InvalidAttrNumber - FirstLowInvalidHeapAttributeNumber,
1865 : parent_privs);
1866 :
1867 : /* And now translate the regular user attributes, using the vars list */
1868 2400 : attno = InvalidAttrNumber;
1869 8187 : foreach(lc, translated_vars)
1870 : {
1871 5787 : Var *var = lfirst_node(Var, lc);
1872 :
1873 5787 : attno++;
1874 5787 : if (var == NULL) /* ignore dropped columns */
1875 255 : continue;
1876 10983 : if (whole_row ||
1877 5451 : bms_is_member(attno - FirstLowInvalidHeapAttributeNumber,
1878 : parent_privs))
1879 1656 : child_privs = bms_add_member(child_privs,
1880 1656 : var->varattno - FirstLowInvalidHeapAttributeNumber);
1881 : }
1882 :
1883 2400 : return child_privs;
1884 : }
1885 :
1886 : /*
1887 : * adjust_appendrel_attrs
1888 : * Copy the specified query or expression and translate Vars referring to a
1889 : * parent rel to refer to the corresponding child rel instead. We also
1890 : * update rtindexes appearing outside Vars, such as resultRelation and
1891 : * jointree relids.
1892 : *
1893 : * Note: this is only applied after conversion of sublinks to subplans,
1894 : * so we don't need to cope with recursion into sub-queries.
1895 : *
1896 : * Note: this is not hugely different from what pullup_replace_vars() does;
1897 : * maybe we should try to fold the two routines together.
1898 : */
1899 : Node *
1900 5011 : adjust_appendrel_attrs(PlannerInfo *root, Node *node, int nappinfos,
1901 : AppendRelInfo **appinfos)
1902 : {
1903 : Node *result;
1904 : adjust_appendrel_attrs_context context;
1905 :
1906 5011 : context.root = root;
1907 5011 : context.nappinfos = nappinfos;
1908 5011 : context.appinfos = appinfos;
1909 :
1910 : /* If there's nothing to adjust, don't call this function. */
1911 5011 : Assert(nappinfos >= 1 && appinfos != NULL);
1912 :
1913 : /*
1914 : * Must be prepared to start with a Query or a bare expression tree.
1915 : */
1916 5011 : if (node && IsA(node, Query))
1917 189 : {
1918 : Query *newnode;
1919 : int cnt;
1920 :
1921 189 : newnode = query_tree_mutator((Query *) node,
1922 : adjust_appendrel_attrs_mutator,
1923 : (void *) &context,
1924 : QTW_IGNORE_RC_SUBQUERIES);
1925 189 : for (cnt = 0; cnt < nappinfos; cnt++)
1926 : {
1927 189 : AppendRelInfo *appinfo = appinfos[cnt];
1928 :
1929 189 : if (newnode->resultRelation == appinfo->parent_relid)
1930 : {
1931 189 : newnode->resultRelation = appinfo->child_relid;
1932 : /* Fix tlist resnos too, if it's inherited UPDATE */
1933 189 : if (newnode->commandType == CMD_UPDATE)
1934 129 : newnode->targetList =
1935 129 : adjust_inherited_tlist(newnode->targetList,
1936 : appinfo);
1937 189 : break;
1938 : }
1939 : }
1940 :
1941 189 : result = (Node *) newnode;
1942 : }
1943 : else
1944 4822 : result = adjust_appendrel_attrs_mutator(node, &context);
1945 :
1946 5011 : return result;
1947 : }
1948 :
1949 : static Node *
1950 19882 : adjust_appendrel_attrs_mutator(Node *node,
1951 : adjust_appendrel_attrs_context *context)
1952 : {
1953 19882 : AppendRelInfo **appinfos = context->appinfos;
1954 19882 : int nappinfos = context->nappinfos;
1955 : int cnt;
1956 :
1957 19882 : if (node == NULL)
1958 5001 : return NULL;
1959 14881 : if (IsA(node, Var))
1960 : {
1961 5679 : Var *var = (Var *) copyObject(node);
1962 5679 : AppendRelInfo *appinfo = NULL;
1963 :
1964 5922 : for (cnt = 0; cnt < nappinfos; cnt++)
1965 : {
1966 5679 : if (var->varno == appinfos[cnt]->parent_relid)
1967 : {
1968 5436 : appinfo = appinfos[cnt];
1969 5436 : break;
1970 : }
1971 : }
1972 :
1973 5679 : if (var->varlevelsup == 0 && appinfo)
1974 : {
1975 5436 : var->varno = appinfo->child_relid;
1976 5436 : var->varnoold = appinfo->child_relid;
1977 5436 : if (var->varattno > 0)
1978 : {
1979 : Node *newnode;
1980 :
1981 4889 : if (var->varattno > list_length(appinfo->translated_vars))
1982 0 : elog(ERROR, "attribute %d of relation \"%s\" does not exist",
1983 : var->varattno, get_rel_name(appinfo->parent_reloid));
1984 4889 : newnode = copyObject(list_nth(appinfo->translated_vars,
1985 : var->varattno - 1));
1986 4889 : if (newnode == NULL)
1987 0 : elog(ERROR, "attribute %d of relation \"%s\" does not exist",
1988 : var->varattno, get_rel_name(appinfo->parent_reloid));
1989 4889 : return newnode;
1990 : }
1991 547 : else if (var->varattno == 0)
1992 : {
1993 : /*
1994 : * Whole-row Var: if we are dealing with named rowtypes, we
1995 : * can use a whole-row Var for the child table plus a coercion
1996 : * step to convert the tuple layout to the parent's rowtype.
1997 : * Otherwise we have to generate a RowExpr.
1998 : */
1999 77 : if (OidIsValid(appinfo->child_reltype))
2000 : {
2001 61 : Assert(var->vartype == appinfo->parent_reltype);
2002 61 : if (appinfo->parent_reltype != appinfo->child_reltype)
2003 : {
2004 41 : ConvertRowtypeExpr *r = makeNode(ConvertRowtypeExpr);
2005 :
2006 41 : r->arg = (Expr *) var;
2007 41 : r->resulttype = appinfo->parent_reltype;
2008 41 : r->convertformat = COERCE_IMPLICIT_CAST;
2009 41 : r->location = -1;
2010 : /* Make sure the Var node has the right type ID, too */
2011 41 : var->vartype = appinfo->child_reltype;
2012 41 : return (Node *) r;
2013 : }
2014 : }
2015 : else
2016 : {
2017 : /*
2018 : * Build a RowExpr containing the translated variables.
2019 : *
2020 : * In practice var->vartype will always be RECORDOID here,
2021 : * so we need to come up with some suitable column names.
2022 : * We use the parent RTE's column names.
2023 : *
2024 : * Note: we can't get here for inheritance cases, so there
2025 : * is no need to worry that translated_vars might contain
2026 : * some dummy NULLs.
2027 : */
2028 : RowExpr *rowexpr;
2029 : List *fields;
2030 : RangeTblEntry *rte;
2031 :
2032 16 : rte = rt_fetch(appinfo->parent_relid,
2033 : context->root->parse->rtable);
2034 16 : fields = copyObject(appinfo->translated_vars);
2035 16 : rowexpr = makeNode(RowExpr);
2036 16 : rowexpr->args = fields;
2037 16 : rowexpr->row_typeid = var->vartype;
2038 16 : rowexpr->row_format = COERCE_IMPLICIT_CAST;
2039 16 : rowexpr->colnames = copyObject(rte->eref->colnames);
2040 16 : rowexpr->location = -1;
2041 :
2042 16 : return (Node *) rowexpr;
2043 : }
2044 : }
2045 : /* system attributes don't need any other translation */
2046 : }
2047 733 : return (Node *) var;
2048 : }
2049 9202 : if (IsA(node, CurrentOfExpr))
2050 : {
2051 24 : CurrentOfExpr *cexpr = (CurrentOfExpr *) copyObject(node);
2052 :
2053 24 : for (cnt = 0; cnt < nappinfos; cnt++)
2054 : {
2055 24 : AppendRelInfo *appinfo = appinfos[cnt];
2056 :
2057 24 : if (cexpr->cvarno == appinfo->parent_relid)
2058 : {
2059 24 : cexpr->cvarno = appinfo->child_relid;
2060 24 : break;
2061 : }
2062 : }
2063 24 : return (Node *) cexpr;
2064 : }
2065 9178 : if (IsA(node, RangeTblRef))
2066 : {
2067 243 : RangeTblRef *rtr = (RangeTblRef *) copyObject(node);
2068 :
2069 297 : for (cnt = 0; cnt < nappinfos; cnt++)
2070 : {
2071 243 : AppendRelInfo *appinfo = appinfos[cnt];
2072 :
2073 243 : if (rtr->rtindex == appinfo->parent_relid)
2074 : {
2075 189 : rtr->rtindex = appinfo->child_relid;
2076 189 : break;
2077 : }
2078 : }
2079 243 : return (Node *) rtr;
2080 : }
2081 8935 : if (IsA(node, JoinExpr))
2082 : {
2083 : /* Copy the JoinExpr node with correct mutation of subnodes */
2084 : JoinExpr *j;
2085 : AppendRelInfo *appinfo;
2086 :
2087 2 : j = (JoinExpr *) expression_tree_mutator(node,
2088 : adjust_appendrel_attrs_mutator,
2089 : (void *) context);
2090 : /* now fix JoinExpr's rtindex (probably never happens) */
2091 4 : for (cnt = 0; cnt < nappinfos; cnt++)
2092 : {
2093 2 : appinfo = appinfos[cnt];
2094 :
2095 2 : if (j->rtindex == appinfo->parent_relid)
2096 : {
2097 0 : j->rtindex = appinfo->child_relid;
2098 0 : break;
2099 : }
2100 : }
2101 2 : return (Node *) j;
2102 : }
2103 8933 : if (IsA(node, PlaceHolderVar))
2104 : {
2105 : /* Copy the PlaceHolderVar node with correct mutation of subnodes */
2106 : PlaceHolderVar *phv;
2107 :
2108 0 : phv = (PlaceHolderVar *) expression_tree_mutator(node,
2109 : adjust_appendrel_attrs_mutator,
2110 : (void *) context);
2111 : /* now fix PlaceHolderVar's relid sets */
2112 0 : if (phv->phlevelsup == 0)
2113 0 : phv->phrels = adjust_child_relids(phv->phrels, context->nappinfos,
2114 : context->appinfos);
2115 0 : return (Node *) phv;
2116 : }
2117 : /* Shouldn't need to handle planner auxiliary nodes here */
2118 8933 : Assert(!IsA(node, SpecialJoinInfo));
2119 8933 : Assert(!IsA(node, AppendRelInfo));
2120 8933 : Assert(!IsA(node, PlaceHolderInfo));
2121 8933 : Assert(!IsA(node, MinMaxAggInfo));
2122 :
2123 : /*
2124 : * We have to process RestrictInfo nodes specially. (Note: although
2125 : * set_append_rel_pathlist will hide RestrictInfos in the parent's
2126 : * baserestrictinfo list from us, it doesn't hide those in joininfo.)
2127 : */
2128 8933 : if (IsA(node, RestrictInfo))
2129 : {
2130 211 : RestrictInfo *oldinfo = (RestrictInfo *) node;
2131 211 : RestrictInfo *newinfo = makeNode(RestrictInfo);
2132 :
2133 : /* Copy all flat-copiable fields */
2134 211 : memcpy(newinfo, oldinfo, sizeof(RestrictInfo));
2135 :
2136 : /* Recursively fix the clause itself */
2137 211 : newinfo->clause = (Expr *)
2138 211 : adjust_appendrel_attrs_mutator((Node *) oldinfo->clause, context);
2139 :
2140 : /* and the modified version, if an OR clause */
2141 211 : newinfo->orclause = (Expr *)
2142 211 : adjust_appendrel_attrs_mutator((Node *) oldinfo->orclause, context);
2143 :
2144 : /* adjust relid sets too */
2145 211 : newinfo->clause_relids = adjust_child_relids(oldinfo->clause_relids,
2146 : context->nappinfos,
2147 : context->appinfos);
2148 211 : newinfo->required_relids = adjust_child_relids(oldinfo->required_relids,
2149 : context->nappinfos,
2150 : context->appinfos);
2151 211 : newinfo->outer_relids = adjust_child_relids(oldinfo->outer_relids,
2152 : context->nappinfos,
2153 : context->appinfos);
2154 211 : newinfo->nullable_relids = adjust_child_relids(oldinfo->nullable_relids,
2155 : context->nappinfos,
2156 : context->appinfos);
2157 211 : newinfo->left_relids = adjust_child_relids(oldinfo->left_relids,
2158 : context->nappinfos,
2159 : context->appinfos);
2160 211 : newinfo->right_relids = adjust_child_relids(oldinfo->right_relids,
2161 : context->nappinfos,
2162 : context->appinfos);
2163 :
2164 : /*
2165 : * Reset cached derivative fields, since these might need to have
2166 : * different values when considering the child relation. Note we
2167 : * don't reset left_ec/right_ec: each child variable is implicitly
2168 : * equivalent to its parent, so still a member of the same EC if any.
2169 : */
2170 211 : newinfo->eval_cost.startup = -1;
2171 211 : newinfo->norm_selec = -1;
2172 211 : newinfo->outer_selec = -1;
2173 211 : newinfo->left_em = NULL;
2174 211 : newinfo->right_em = NULL;
2175 211 : newinfo->scansel_cache = NIL;
2176 211 : newinfo->left_bucketsize = -1;
2177 211 : newinfo->right_bucketsize = -1;
2178 211 : newinfo->left_mcvfreq = -1;
2179 211 : newinfo->right_mcvfreq = -1;
2180 :
2181 211 : return (Node *) newinfo;
2182 : }
2183 :
2184 : /*
2185 : * NOTE: we do not need to recurse into sublinks, because they should
2186 : * already have been converted to subplans before we see them.
2187 : */
2188 8722 : Assert(!IsA(node, SubLink));
2189 8722 : Assert(!IsA(node, Query));
2190 :
2191 8722 : return expression_tree_mutator(node, adjust_appendrel_attrs_mutator,
2192 : (void *) context);
2193 : }
2194 :
2195 : /*
2196 : * Substitute child relids for parent relids in a Relid set. The array of
2197 : * appinfos specifies the substitutions to be performed.
2198 : */
2199 : static Relids
2200 1266 : adjust_child_relids(Relids relids, int nappinfos, AppendRelInfo **appinfos)
2201 : {
2202 1266 : Bitmapset *result = NULL;
2203 : int cnt;
2204 :
2205 2532 : for (cnt = 0; cnt < nappinfos; cnt++)
2206 : {
2207 1266 : AppendRelInfo *appinfo = appinfos[cnt];
2208 :
2209 : /* Remove parent, add child */
2210 1266 : if (bms_is_member(appinfo->parent_relid, relids))
2211 : {
2212 : /* Make a copy if we are changing the set. */
2213 409 : if (!result)
2214 409 : result = bms_copy(relids);
2215 :
2216 409 : result = bms_del_member(result, appinfo->parent_relid);
2217 409 : result = bms_add_member(result, appinfo->child_relid);
2218 : }
2219 : }
2220 :
2221 : /* If we made any changes, return the modified copy. */
2222 1266 : if (result)
2223 409 : return result;
2224 :
2225 : /* Otherwise, return the original set without modification. */
2226 857 : return relids;
2227 : }
2228 :
2229 : /*
2230 : * Adjust the targetlist entries of an inherited UPDATE operation
2231 : *
2232 : * The expressions have already been fixed, but we have to make sure that
2233 : * the target resnos match the child table (they may not, in the case of
2234 : * a column that was added after-the-fact by ALTER TABLE). In some cases
2235 : * this can force us to re-order the tlist to preserve resno ordering.
2236 : * (We do all this work in special cases so that preptlist.c is fast for
2237 : * the typical case.)
2238 : *
2239 : * The given tlist has already been through expression_tree_mutator;
2240 : * therefore the TargetEntry nodes are fresh copies that it's okay to
2241 : * scribble on.
2242 : *
2243 : * Note that this is not needed for INSERT because INSERT isn't inheritable.
2244 : */
2245 : static List *
2246 129 : adjust_inherited_tlist(List *tlist, AppendRelInfo *context)
2247 : {
2248 129 : bool changed_it = false;
2249 : ListCell *tl;
2250 : List *new_tlist;
2251 : bool more;
2252 : int attrno;
2253 :
2254 : /* This should only happen for an inheritance case, not UNION ALL */
2255 129 : Assert(OidIsValid(context->parent_reloid));
2256 :
2257 : /* Scan tlist and update resnos to match attnums of child rel */
2258 389 : foreach(tl, tlist)
2259 : {
2260 260 : TargetEntry *tle = (TargetEntry *) lfirst(tl);
2261 : Var *childvar;
2262 :
2263 260 : if (tle->resjunk)
2264 129 : continue; /* ignore junk items */
2265 :
2266 : /* Look up the translation of this column: it must be a Var */
2267 262 : if (tle->resno <= 0 ||
2268 131 : tle->resno > list_length(context->translated_vars))
2269 0 : elog(ERROR, "attribute %d of relation \"%s\" does not exist",
2270 : tle->resno, get_rel_name(context->parent_reloid));
2271 131 : childvar = (Var *) list_nth(context->translated_vars, tle->resno - 1);
2272 131 : if (childvar == NULL || !IsA(childvar, Var))
2273 0 : elog(ERROR, "attribute %d of relation \"%s\" does not exist",
2274 : tle->resno, get_rel_name(context->parent_reloid));
2275 :
2276 131 : if (tle->resno != childvar->varattno)
2277 : {
2278 22 : tle->resno = childvar->varattno;
2279 22 : changed_it = true;
2280 : }
2281 : }
2282 :
2283 : /*
2284 : * If we changed anything, re-sort the tlist by resno, and make sure
2285 : * resjunk entries have resnos above the last real resno. The sort
2286 : * algorithm is a bit stupid, but for such a seldom-taken path, small is
2287 : * probably better than fast.
2288 : */
2289 129 : if (!changed_it)
2290 108 : return tlist;
2291 :
2292 21 : new_tlist = NIL;
2293 21 : more = true;
2294 67 : for (attrno = 1; more; attrno++)
2295 : {
2296 46 : more = false;
2297 142 : foreach(tl, tlist)
2298 : {
2299 96 : TargetEntry *tle = (TargetEntry *) lfirst(tl);
2300 :
2301 96 : if (tle->resjunk)
2302 46 : continue; /* ignore junk items */
2303 :
2304 50 : if (tle->resno == attrno)
2305 22 : new_tlist = lappend(new_tlist, tle);
2306 28 : else if (tle->resno > attrno)
2307 26 : more = true;
2308 : }
2309 : }
2310 :
2311 64 : foreach(tl, tlist)
2312 : {
2313 43 : TargetEntry *tle = (TargetEntry *) lfirst(tl);
2314 :
2315 43 : if (!tle->resjunk)
2316 22 : continue; /* here, ignore non-junk items */
2317 :
2318 21 : tle->resno = attrno;
2319 21 : new_tlist = lappend(new_tlist, tle);
2320 21 : attrno++;
2321 : }
2322 :
2323 21 : return new_tlist;
2324 : }
2325 :
2326 : /*
2327 : * adjust_appendrel_attrs_multilevel
2328 : * Apply Var translations from a toplevel appendrel parent down to a child.
2329 : *
2330 : * In some cases we need to translate expressions referencing a parent relation
2331 : * to reference an appendrel child that's multiple levels removed from it.
2332 : */
2333 : Node *
2334 45 : adjust_appendrel_attrs_multilevel(PlannerInfo *root, Node *node,
2335 : Relids child_relids,
2336 : Relids top_parent_relids)
2337 : {
2338 : AppendRelInfo **appinfos;
2339 45 : Bitmapset *parent_relids = NULL;
2340 : int nappinfos;
2341 : int cnt;
2342 :
2343 45 : Assert(bms_num_members(child_relids) == bms_num_members(top_parent_relids));
2344 :
2345 45 : appinfos = find_appinfos_by_relids(root, child_relids, &nappinfos);
2346 :
2347 : /* Construct relids set for the immediate parent of given child. */
2348 90 : for (cnt = 0; cnt < nappinfos; cnt++)
2349 : {
2350 45 : AppendRelInfo *appinfo = appinfos[cnt];
2351 :
2352 45 : parent_relids = bms_add_member(parent_relids, appinfo->parent_relid);
2353 : }
2354 :
2355 : /* Recurse if immediate parent is not the top parent. */
2356 45 : if (!bms_equal(parent_relids, top_parent_relids))
2357 18 : node = adjust_appendrel_attrs_multilevel(root, node, parent_relids,
2358 : top_parent_relids);
2359 :
2360 : /* Now translate for this child */
2361 45 : node = adjust_appendrel_attrs(root, node, nappinfos, appinfos);
2362 :
2363 45 : pfree(appinfos);
2364 :
2365 45 : return node;
2366 : }
2367 :
2368 : /*
2369 : * find_appinfos_by_relids
2370 : * Find AppendRelInfo structures for all relations specified by relids.
2371 : *
2372 : * The AppendRelInfos are returned in an array, which can be pfree'd by the
2373 : * caller. *nappinfos is set to the the number of entries in the array.
2374 : */
2375 : AppendRelInfo **
2376 45 : find_appinfos_by_relids(PlannerInfo *root, Relids relids, int *nappinfos)
2377 : {
2378 : ListCell *lc;
2379 : AppendRelInfo **appinfos;
2380 45 : int cnt = 0;
2381 :
2382 45 : *nappinfos = bms_num_members(relids);
2383 45 : appinfos = (AppendRelInfo **) palloc(sizeof(AppendRelInfo *) * *nappinfos);
2384 :
2385 139 : foreach(lc, root->append_rel_list)
2386 : {
2387 139 : AppendRelInfo *appinfo = lfirst(lc);
2388 :
2389 139 : if (bms_is_member(appinfo->child_relid, relids))
2390 : {
2391 45 : appinfos[cnt] = appinfo;
2392 45 : cnt++;
2393 :
2394 : /* Stop when we have gathered all the AppendRelInfos. */
2395 45 : if (cnt == *nappinfos)
2396 45 : return appinfos;
2397 : }
2398 : }
2399 :
2400 : /* Should have found the entries ... */
2401 0 : elog(ERROR, "did not find all requested child rels in append_rel_list");
2402 : return NULL; /* not reached */
2403 : }
|