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