]> granicus.if.org Git - postgresql/blob - src/backend/optimizer/prep/prepunion.c
4d5adc4d47bc45334041c8cbacb907486f3d544e
[postgresql] / src / backend / optimizer / prep / prepunion.c
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 is also some code here to support planning of queries that use
8  * inheritance (SELECT FROM foo*).      This no longer has much connection
9  * to the processing of UNION queries, but it's still here.
10  *
11  *
12  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
13  * Portions Copyright (c) 1994, Regents of the University of California
14  *
15  *
16  * IDENTIFICATION
17  *        $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.84 2003/01/05 00:56:40 tgl Exp $
18  *
19  *-------------------------------------------------------------------------
20  */
21 #include "postgres.h"
22
23
24 #include "catalog/pg_type.h"
25 #include "nodes/makefuncs.h"
26 #include "optimizer/clauses.h"
27 #include "optimizer/plancat.h"
28 #include "optimizer/planmain.h"
29 #include "optimizer/planner.h"
30 #include "optimizer/prep.h"
31 #include "optimizer/tlist.h"
32 #include "parser/parse_clause.h"
33 #include "parser/parse_coerce.h"
34 #include "parser/parsetree.h"
35 #include "utils/lsyscache.h"
36
37 /* macros borrowed from expression_tree_mutator */
38
39 #define FLATCOPY(newnode, node, nodetype)  \
40         ( (newnode) = makeNode(nodetype), \
41           memcpy((newnode), (node), sizeof(nodetype)) )
42
43 typedef struct
44 {
45         Index           old_rt_index;
46         Index           new_rt_index;
47         Oid                     old_relid;
48         Oid                     new_relid;
49 } adjust_inherited_attrs_context;
50
51 static Plan *recurse_set_operations(Node *setOp, Query *parse,
52                                            List *colTypes, bool junkOK,
53                                            int flag, List *refnames_tlist);
54 static Plan *generate_union_plan(SetOperationStmt *op, Query *parse,
55                                         List *refnames_tlist);
56 static Plan *generate_nonunion_plan(SetOperationStmt *op, Query *parse,
57                                            List *refnames_tlist);
58 static List *recurse_union_children(Node *setOp, Query *parse,
59                                            SetOperationStmt *top_union,
60                                            List *refnames_tlist);
61 static List *generate_setop_tlist(List *colTypes, int flag,
62                                          bool hack_constants,
63                                          List *input_tlist,
64                                          List *refnames_tlist);
65 static List *generate_append_tlist(List *colTypes, bool flag,
66                                           List *input_plans,
67                                           List *refnames_tlist);
68 static Node *adjust_inherited_attrs_mutator(Node *node,
69                                                            adjust_inherited_attrs_context *context);
70 static List *adjust_inherited_tlist(List *tlist, Oid new_relid);
71
72
73 /*
74  * plan_set_operations
75  *
76  *        Plans the queries for a tree of set operations (UNION/INTERSECT/EXCEPT)
77  *
78  * This routine only deals with the setOperations tree of the given query.
79  * Any top-level ORDER BY requested in parse->sortClause will be added
80  * when we return to grouping_planner.
81  */
82 Plan *
83 plan_set_operations(Query *parse)
84 {
85         SetOperationStmt *topop = (SetOperationStmt *) parse->setOperations;
86         Node       *node;
87         Query      *leftmostQuery;
88
89         Assert(topop && IsA(topop, SetOperationStmt));
90
91         /*
92          * Find the leftmost component Query.  We need to use its column names
93          * for all generated tlists (else SELECT INTO won't work right).
94          */
95         node = topop->larg;
96         while (node && IsA(node, SetOperationStmt))
97                 node = ((SetOperationStmt *) node)->larg;
98         Assert(node && IsA(node, RangeTblRef));
99         leftmostQuery = rt_fetch(((RangeTblRef *) node)->rtindex,
100                                                          parse->rtable)->subquery;
101         Assert(leftmostQuery != NULL);
102
103         /*
104          * Recurse on setOperations tree to generate plans for set ops. The
105          * final output plan should have just the column types shown as the
106          * output from the top-level node, plus possibly a resjunk working
107          * column (we can rely on upper-level nodes to deal with that).
108          */
109         return recurse_set_operations((Node *) topop, parse,
110                                                                   topop->colTypes, true, -1,
111                                                                   leftmostQuery->targetList);
112 }
113
114 /*
115  * recurse_set_operations
116  *        Recursively handle one step in a tree of set operations
117  *
118  * colTypes: integer list of type OIDs of expected output columns
119  * junkOK: if true, child resjunk columns may be left in the result
120  * flag: if >= 0, add a resjunk output column indicating value of flag
121  * refnames_tlist: targetlist to take column names from
122  */
123 static Plan *
124 recurse_set_operations(Node *setOp, Query *parse,
125                                            List *colTypes, bool junkOK,
126                                            int flag, List *refnames_tlist)
127 {
128         if (IsA(setOp, RangeTblRef))
129         {
130                 RangeTblRef *rtr = (RangeTblRef *) setOp;
131                 RangeTblEntry *rte = rt_fetch(rtr->rtindex, parse->rtable);
132                 Query      *subquery = rte->subquery;
133                 Plan       *subplan,
134                                    *plan;
135
136                 Assert(subquery != NULL);
137
138                 /*
139                  * Generate plan for primitive subquery
140                  */
141                 subplan = subquery_planner(subquery,
142                                                                    -1.0 /* default case */ );
143
144                 /*
145                  * Add a SubqueryScan with the caller-requested targetlist
146                  */
147                 plan = (Plan *)
148                         make_subqueryscan(generate_setop_tlist(colTypes, flag, true,
149                                                                                                    subplan->targetlist,
150                                                                                                    refnames_tlist),
151                                                           NIL,
152                                                           rtr->rtindex,
153                                                           subplan);
154                 return plan;
155         }
156         else if (IsA(setOp, SetOperationStmt))
157         {
158                 SetOperationStmt *op = (SetOperationStmt *) setOp;
159                 Plan       *plan;
160
161                 /* UNIONs are much different from INTERSECT/EXCEPT */
162                 if (op->op == SETOP_UNION)
163                         plan = generate_union_plan(op, parse, refnames_tlist);
164                 else
165                         plan = generate_nonunion_plan(op, parse, refnames_tlist);
166
167                 /*
168                  * If necessary, add a Result node to project the caller-requested
169                  * output columns.
170                  *
171                  * XXX you don't really want to know about this: setrefs.c will apply
172                  * replace_vars_with_subplan_refs() to the Result node's tlist.
173                  * This would fail if the Vars generated by generate_setop_tlist()
174                  * were not exactly equal() to the corresponding tlist entries of
175                  * the subplan.  However, since the subplan was generated by
176                  * generate_union_plan() or generate_nonunion_plan(), and hence
177                  * its tlist was generated by generate_append_tlist(), this will
178                  * work.
179                  */
180                 if (flag >= 0 ||
181                         !tlist_same_datatypes(plan->targetlist, colTypes, junkOK))
182                 {
183                         plan = (Plan *)
184                                 make_result(generate_setop_tlist(colTypes, flag, false,
185                                                                                                  plan->targetlist,
186                                                                                                  refnames_tlist),
187                                                         NULL,
188                                                         plan);
189                 }
190                 return plan;
191         }
192         else
193         {
194                 elog(ERROR, "recurse_set_operations: unexpected node %d",
195                          (int) nodeTag(setOp));
196                 return NULL;                    /* keep compiler quiet */
197         }
198 }
199
200 /*
201  * Generate plan for a UNION or UNION ALL node
202  */
203 static Plan *
204 generate_union_plan(SetOperationStmt *op, Query *parse,
205                                         List *refnames_tlist)
206 {
207         List       *planlist;
208         List       *tlist;
209         Plan       *plan;
210
211         /*
212          * If any of my children are identical UNION nodes (same op, all-flag,
213          * and colTypes) then they can be merged into this node so that we
214          * generate only one Append and Sort for the lot.  Recurse to find
215          * such nodes and compute their children's plans.
216          */
217         planlist = nconc(recurse_union_children(op->larg, parse,
218                                                                                         op, refnames_tlist),
219                                          recurse_union_children(op->rarg, parse,
220                                                                                         op, refnames_tlist));
221
222         /*
223          * Generate tlist for Append plan node.
224          *
225          * The tlist for an Append plan isn't important as far as the Append is
226          * concerned, but we must make it look real anyway for the benefit of
227          * the next plan level up.
228          */
229         tlist = generate_append_tlist(op->colTypes, false,
230                                                                   planlist, refnames_tlist);
231
232         /*
233          * Append the child results together.
234          */
235         plan = (Plan *) make_append(planlist, false, tlist);
236
237         /*
238          * For UNION ALL, we just need the Append plan.  For UNION, need to
239          * add Sort and Unique nodes to produce unique output.
240          */
241         if (!op->all)
242         {
243                 List       *sortList;
244
245                 tlist = new_unsorted_tlist(tlist);
246                 sortList = addAllTargetsToSortList(NIL, tlist);
247                 plan = make_sortplan(parse, tlist, plan, sortList);
248                 plan = (Plan *) make_unique(tlist, plan, copyObject(sortList));
249         }
250         return plan;
251 }
252
253 /*
254  * Generate plan for an INTERSECT, INTERSECT ALL, EXCEPT, or EXCEPT ALL node
255  */
256 static Plan *
257 generate_nonunion_plan(SetOperationStmt *op, Query *parse,
258                                            List *refnames_tlist)
259 {
260         Plan       *lplan,
261                            *rplan,
262                            *plan;
263         List       *tlist,
264                            *sortList,
265                            *planlist;
266         SetOpCmd        cmd;
267
268         /* Recurse on children, ensuring their outputs are marked */
269         lplan = recurse_set_operations(op->larg, parse,
270                                                                    op->colTypes, false, 0,
271                                                                    refnames_tlist);
272         rplan = recurse_set_operations(op->rarg, parse,
273                                                                    op->colTypes, false, 1,
274                                                                    refnames_tlist);
275         planlist = makeList2(lplan, rplan);
276
277         /*
278          * Generate tlist for Append plan node.
279          *
280          * The tlist for an Append plan isn't important as far as the Append is
281          * concerned, but we must make it look real anyway for the benefit of
282          * the next plan level up.      In fact, it has to be real enough that the
283          * flag column is shown as a variable not a constant, else setrefs.c
284          * will get confused.
285          */
286         tlist = generate_append_tlist(op->colTypes, true,
287                                                                   planlist, refnames_tlist);
288
289         /*
290          * Append the child results together.
291          */
292         plan = (Plan *) make_append(planlist, false, tlist);
293
294         /*
295          * Sort the child results, then add a SetOp plan node to generate the
296          * correct output.
297          */
298         tlist = new_unsorted_tlist(tlist);
299         sortList = addAllTargetsToSortList(NIL, tlist);
300         plan = make_sortplan(parse, tlist, plan, sortList);
301         switch (op->op)
302         {
303                 case SETOP_INTERSECT:
304                         cmd = op->all ? SETOPCMD_INTERSECT_ALL : SETOPCMD_INTERSECT;
305                         break;
306                 case SETOP_EXCEPT:
307                         cmd = op->all ? SETOPCMD_EXCEPT_ALL : SETOPCMD_EXCEPT;
308                         break;
309                 default:
310                         elog(ERROR, "generate_nonunion_plan: bogus operation code");
311                         cmd = SETOPCMD_INTERSECT;       /* keep compiler quiet */
312                         break;
313         }
314         plan = (Plan *) make_setop(cmd, tlist, plan, sortList,
315                                                            length(op->colTypes) + 1);
316         return plan;
317 }
318
319 /*
320  * Pull up children of a UNION node that are identically-propertied UNIONs.
321  *
322  * NOTE: we can also pull a UNION ALL up into a UNION, since the distinct
323  * output rows will be lost anyway.
324  */
325 static List *
326 recurse_union_children(Node *setOp, Query *parse,
327                                            SetOperationStmt *top_union,
328                                            List *refnames_tlist)
329 {
330         if (IsA(setOp, SetOperationStmt))
331         {
332                 SetOperationStmt *op = (SetOperationStmt *) setOp;
333
334                 if (op->op == top_union->op &&
335                         (op->all == top_union->all || op->all) &&
336                         equali(op->colTypes, top_union->colTypes))
337                 {
338                         /* Same UNION, so fold children into parent's subplan list */
339                         return nconc(recurse_union_children(op->larg, parse,
340                                                                                                 top_union,
341                                                                                                 refnames_tlist),
342                                                  recurse_union_children(op->rarg, parse,
343                                                                                                 top_union,
344                                                                                                 refnames_tlist));
345                 }
346         }
347
348         /*
349          * Not same, so plan this child separately.
350          *
351          * Note we disallow any resjunk columns in child results.  This is
352          * necessary since the Append node that implements the union won't do
353          * any projection, and upper levels will get confused if some of our
354          * output tuples have junk and some don't.  This case only arises when
355          * we have an EXCEPT or INTERSECT as child, else there won't be
356          * resjunk anyway.
357          */
358         return makeList1(recurse_set_operations(setOp, parse,
359                                                                                         top_union->colTypes, false,
360                                                                                         -1, refnames_tlist));
361 }
362
363 /*
364  * Generate targetlist for a set-operation plan node
365  *
366  * colTypes: column datatypes for non-junk columns
367  * flag: -1 if no flag column needed, 0 or 1 to create a const flag column
368  * hack_constants: true to copy up constants (see comments in code)
369  * input_tlist: targetlist of this node's input node
370  * refnames_tlist: targetlist to take column names from
371  */
372 static List *
373 generate_setop_tlist(List *colTypes, int flag,
374                                          bool hack_constants,
375                                          List *input_tlist,
376                                          List *refnames_tlist)
377 {
378         List       *tlist = NIL;
379         int                     resno = 1;
380         List       *i;
381         Resdom     *resdom;
382         Node       *expr;
383
384         foreach(i, colTypes)
385         {
386                 Oid                     colType = (Oid) lfirsti(i);
387                 TargetEntry *inputtle = (TargetEntry *) lfirst(input_tlist);
388                 TargetEntry *reftle = (TargetEntry *) lfirst(refnames_tlist);
389                 int32           colTypmod;
390
391                 Assert(inputtle->resdom->resno == resno);
392                 Assert(reftle->resdom->resno == resno);
393                 Assert(!inputtle->resdom->resjunk);
394                 Assert(!reftle->resdom->resjunk);
395
396                 /*
397                  * Generate columns referencing input columns and having
398                  * appropriate data types and column names.  Insert datatype
399                  * coercions where necessary.
400                  *
401                  * HACK: constants in the input's targetlist are copied up as-is
402                  * rather than being referenced as subquery outputs.  This is
403                  * mainly to ensure that when we try to coerce them to the output
404                  * column's datatype, the right things happen for UNKNOWN
405                  * constants.  But do this only at the first level of
406                  * subquery-scan plans; we don't want phony constants appearing in
407                  * the output tlists of upper-level nodes!
408                  */
409                 if (hack_constants && inputtle->expr && IsA(inputtle->expr, Const))
410                         expr = (Node *) inputtle->expr;
411                 else
412                         expr = (Node *) makeVar(0,
413                                                                         inputtle->resdom->resno,
414                                                                         inputtle->resdom->restype,
415                                                                         inputtle->resdom->restypmod,
416                                                                         0);
417                 if (inputtle->resdom->restype == colType)
418                 {
419                         /* no coercion needed, and believe the input typmod */
420                         colTypmod = inputtle->resdom->restypmod;
421                 }
422                 else
423                 {
424                         expr = coerce_to_common_type(expr,
425                                                                                  colType,
426                                                                                  "UNION/INTERSECT/EXCEPT");
427                         colTypmod = -1;
428                 }
429                 resdom = makeResdom((AttrNumber) resno++,
430                                                         colType,
431                                                         colTypmod,
432                                                         pstrdup(reftle->resdom->resname),
433                                                         false);
434                 tlist = lappend(tlist, makeTargetEntry(resdom, (Expr *) expr));
435                 input_tlist = lnext(input_tlist);
436                 refnames_tlist = lnext(refnames_tlist);
437         }
438
439         if (flag >= 0)
440         {
441                 /* Add a resjunk flag column */
442                 resdom = makeResdom((AttrNumber) resno++,
443                                                         INT4OID,
444                                                         -1,
445                                                         pstrdup("flag"),
446                                                         true);
447                 /* flag value is the given constant */
448                 expr = (Node *) makeConst(INT4OID,
449                                                                   sizeof(int4),
450                                                                   Int32GetDatum(flag),
451                                                                   false,
452                                                                   true);
453                 tlist = lappend(tlist, makeTargetEntry(resdom, (Expr *) expr));
454         }
455
456         return tlist;
457 }
458
459 /*
460  * Generate targetlist for a set-operation Append node
461  *
462  * colTypes: column datatypes for non-junk columns
463  * flag: true to create a flag column copied up from subplans
464  * input_plans: list of sub-plans of the Append
465  * refnames_tlist: targetlist to take column names from
466  *
467  * The entries in the Append's targetlist should always be simple Vars;
468  * we just have to make sure they have the right datatypes and typmods.
469  */
470 static List *
471 generate_append_tlist(List *colTypes, bool flag,
472                                           List *input_plans,
473                                           List *refnames_tlist)
474 {
475         List       *tlist = NIL;
476         int                     resno = 1;
477         List       *curColType;
478         int                     colindex;
479         Resdom     *resdom;
480         Node       *expr;
481         List       *planl;
482         int32      *colTypmods;
483
484         /*
485          * First extract typmods to use.
486          *
487          * If the inputs all agree on type and typmod of a particular column, use
488          * that typmod; else use -1.
489          */
490         colTypmods = (int32 *) palloc(length(colTypes) * sizeof(int32));
491
492         foreach(planl, input_plans)
493         {
494                 Plan       *subplan = (Plan *) lfirst(planl);
495                 List       *subtlist;
496
497                 curColType = colTypes;
498                 colindex = 0;
499                 foreach(subtlist, subplan->targetlist)
500                 {
501                         TargetEntry *subtle = (TargetEntry *) lfirst(subtlist);
502
503                         if (subtle->resdom->resjunk)
504                                 continue;
505                         Assert(curColType != NIL);
506                         if (subtle->resdom->restype == (Oid) lfirsti(curColType))
507                         {
508                                 /* If first subplan, copy the typmod; else compare */
509                                 if (planl == input_plans)
510                                         colTypmods[colindex] = subtle->resdom->restypmod;
511                                 else if (subtle->resdom->restypmod != colTypmods[colindex])
512                                         colTypmods[colindex] = -1;
513                         }
514                         else
515                         {
516                                 /* types disagree, so force typmod to -1 */
517                                 colTypmods[colindex] = -1;
518                         }
519                         curColType = lnext(curColType);
520                         colindex++;
521                 }
522                 Assert(curColType == NIL);
523         }
524
525         /*
526          * Now we can build the tlist for the Append.
527          */
528         colindex = 0;
529         foreach(curColType, colTypes)
530         {
531                 Oid                     colType = (Oid) lfirsti(curColType);
532                 int32           colTypmod = colTypmods[colindex++];
533                 TargetEntry *reftle = (TargetEntry *) lfirst(refnames_tlist);
534
535                 Assert(reftle->resdom->resno == resno);
536                 Assert(!reftle->resdom->resjunk);
537                 expr = (Node *) makeVar(0,
538                                                                 resno,
539                                                                 colType,
540                                                                 colTypmod,
541                                                                 0);
542                 resdom = makeResdom((AttrNumber) resno++,
543                                                         colType,
544                                                         colTypmod,
545                                                         pstrdup(reftle->resdom->resname),
546                                                         false);
547                 tlist = lappend(tlist, makeTargetEntry(resdom, (Expr *) expr));
548                 refnames_tlist = lnext(refnames_tlist);
549         }
550
551         if (flag)
552         {
553                 /* Add a resjunk flag column */
554                 resdom = makeResdom((AttrNumber) resno++,
555                                                         INT4OID,
556                                                         -1,
557                                                         pstrdup("flag"),
558                                                         true);
559                 /* flag value is shown as copied up from subplan */
560                 expr = (Node *) makeVar(0,
561                                                                 resdom->resno,
562                                                                 INT4OID,
563                                                                 -1,
564                                                                 0);
565                 tlist = lappend(tlist, makeTargetEntry(resdom, (Expr *) expr));
566         }
567
568         pfree(colTypmods);
569
570         return tlist;
571 }
572
573 /*
574  * Does tlist have same datatypes as requested colTypes?
575  *
576  * Resjunk columns are ignored if junkOK is true; otherwise presence of
577  * a resjunk column will always cause a 'false' result.
578  */
579 bool
580 tlist_same_datatypes(List *tlist, List *colTypes, bool junkOK)
581 {
582         List       *i;
583
584         foreach(i, tlist)
585         {
586                 TargetEntry *tle = (TargetEntry *) lfirst(i);
587
588                 if (tle->resdom->resjunk)
589                 {
590                         if (!junkOK)
591                                 return false;
592                 }
593                 else
594                 {
595                         if (colTypes == NIL)
596                                 return false;
597                         if (tle->resdom->restype != (Oid) lfirsti(colTypes))
598                                 return false;
599                         colTypes = lnext(colTypes);
600                 }
601         }
602         if (colTypes != NIL)
603                 return false;
604         return true;
605 }
606
607
608 /*
609  * find_all_inheritors -
610  *              Returns an integer list of relids including the given rel plus
611  *              all relations that inherit from it, directly or indirectly.
612  */
613 List *
614 find_all_inheritors(Oid parentrel)
615 {
616         List       *examined_relids = NIL;
617         List       *unexamined_relids = makeListi1(parentrel);
618
619         /*
620          * While the queue of unexamined relids is nonempty, remove the first
621          * element, mark it examined, and find its direct descendants. NB:
622          * cannot use foreach(), since we modify the queue inside loop.
623          */
624         while (unexamined_relids != NIL)
625         {
626                 Oid                     currentrel = lfirsti(unexamined_relids);
627                 List       *currentchildren;
628
629                 unexamined_relids = lnext(unexamined_relids);
630                 examined_relids = lappendi(examined_relids, currentrel);
631                 currentchildren = find_inheritance_children(currentrel);
632
633                 /*
634                  * Add to the queue only those children not already seen. This
635                  * avoids making duplicate entries in case of multiple inheritance
636                  * paths from the same parent.  (It'll also keep us from getting
637                  * into an infinite loop, though theoretically there can't be any
638                  * cycles in the inheritance graph anyway.)
639                  */
640                 currentchildren = set_differencei(currentchildren, examined_relids);
641                 unexamined_relids = set_unioni(unexamined_relids, currentchildren);
642         }
643
644         return examined_relids;
645 }
646
647 /*
648  * expand_inherted_rtentry
649  *              Check whether a rangetable entry represents an inheritance set.
650  *              If so, add entries for all the child tables to the query's
651  *              rangetable, and return an integer list of RT indexes for the
652  *              whole inheritance set (parent and children).
653  *              If not, return NIL.
654  *
655  * When dup_parent is false, the initially given RT index is part of the
656  * returned list (if any).      When dup_parent is true, the given RT index
657  * is *not* in the returned list; a duplicate RTE will be made for the
658  * parent table.
659  *
660  * A childless table is never considered to be an inheritance set; therefore
661  * the result will never be a one-element list.  It'll be either empty
662  * or have two or more elements.
663  *
664  * NOTE: after this routine executes, the specified RTE will always have
665  * its inh flag cleared, whether or not there were any children.  This
666  * ensures we won't expand the same RTE twice, which would otherwise occur
667  * for the case of an inherited UPDATE/DELETE target relation.
668  */
669 List *
670 expand_inherted_rtentry(Query *parse, Index rti, bool dup_parent)
671 {
672         RangeTblEntry *rte = rt_fetch(rti, parse->rtable);
673         Oid                     parentOID;
674         List       *inhOIDs;
675         List       *inhRTIs;
676         List       *l;
677
678         /* Does RT entry allow inheritance? */
679         if (!rte->inh)
680                 return NIL;
681         Assert(rte->rtekind == RTE_RELATION);
682         /* Always clear the parent's inh flag, see above comments */
683         rte->inh = false;
684         /* Fast path for common case of childless table */
685         parentOID = rte->relid;
686         if (!has_subclass(parentOID))
687                 return NIL;
688         /* Scan for all members of inheritance set */
689         inhOIDs = find_all_inheritors(parentOID);
690
691         /*
692          * Check that there's at least one descendant, else treat as no-child
693          * case.  This could happen despite above has_subclass() check, if
694          * table once had a child but no longer does.
695          */
696         if (lnext(inhOIDs) == NIL)
697                 return NIL;
698         /* OK, it's an inheritance set; expand it */
699         if (dup_parent)
700                 inhRTIs = NIL;
701         else
702                 inhRTIs = makeListi1(rti);              /* include original RTE in result */
703
704         foreach(l, inhOIDs)
705         {
706                 Oid                     childOID = (Oid) lfirsti(l);
707                 RangeTblEntry *childrte;
708                 Index           childRTindex;
709
710                 /* parent will be in the list too; skip it if not dup requested */
711                 if (childOID == parentOID && !dup_parent)
712                         continue;
713
714                 /*
715                  * Build an RTE for the child, and attach to query's rangetable
716                  * list. We copy most fields of the parent's RTE, but replace
717                  * relation real name and OID.  Note that inh will be false at
718                  * this point.
719                  */
720                 childrte = copyObject(rte);
721                 childrte->relid = childOID;
722                 parse->rtable = lappend(parse->rtable, childrte);
723                 childRTindex = length(parse->rtable);
724
725                 inhRTIs = lappendi(inhRTIs, childRTindex);
726         }
727
728         return inhRTIs;
729 }
730
731 /*
732  * adjust_inherited_attrs
733  *        Copy the specified query or expression and translate Vars referring
734  *        to old_rt_index to refer to new_rt_index.
735  *
736  * We also adjust varattno to match the new table by column name, rather
737  * than column number.  This hack makes it possible for child tables to have
738  * different column positions for the "same" attribute as a parent, which
739  * helps ALTER TABLE ADD COLUMN.  Unfortunately this isn't nearly enough to
740  * make it work transparently; there are other places where things fall down
741  * if children and parents don't have the same column numbers for inherited
742  * attributes.  It'd be better to rip this code out and fix ALTER TABLE...
743  */
744 Node *
745 adjust_inherited_attrs(Node *node,
746                                            Index old_rt_index, Oid old_relid,
747                                            Index new_rt_index, Oid new_relid)
748 {
749         adjust_inherited_attrs_context context;
750
751         /* Handle simple case simply... */
752         if (old_rt_index == new_rt_index)
753         {
754                 Assert(old_relid == new_relid);
755                 return copyObject(node);
756         }
757
758         context.old_rt_index = old_rt_index;
759         context.new_rt_index = new_rt_index;
760         context.old_relid = old_relid;
761         context.new_relid = new_relid;
762
763         /*
764          * Must be prepared to start with a Query or a bare expression tree.
765          */
766         if (node && IsA(node, Query))
767         {
768                 Query      *query = (Query *) node;
769                 Query      *newnode;
770
771                 FLATCOPY(newnode, query, Query);
772                 query_tree_mutator(newnode, adjust_inherited_attrs_mutator,
773                                                    (void *) &context, QTW_IGNORE_SUBQUERIES);
774                 if (newnode->resultRelation == old_rt_index)
775                 {
776                         newnode->resultRelation = new_rt_index;
777                         /* Fix tlist resnos too, if it's inherited UPDATE */
778                         if (newnode->commandType == CMD_UPDATE)
779                                 newnode->targetList =
780                                         adjust_inherited_tlist(newnode->targetList,
781                                                                                    new_relid);
782                 }
783                 return (Node *) newnode;
784         }
785         else
786                 return adjust_inherited_attrs_mutator(node, &context);
787 }
788
789 static Node *
790 adjust_inherited_attrs_mutator(Node *node,
791                                                            adjust_inherited_attrs_context *context)
792 {
793         if (node == NULL)
794                 return NULL;
795         if (IsA(node, Var))
796         {
797                 Var                *var = (Var *) copyObject(node);
798
799                 if (var->varlevelsup == 0 &&
800                         var->varno == context->old_rt_index)
801                 {
802                         var->varno = context->new_rt_index;
803                         if (var->varattno > 0)
804                         {
805                                 char       *attname = get_attname(context->old_relid,
806                                                                                                   var->varattno);
807
808                                 var->varattno = get_attnum(context->new_relid, attname);
809                                 if (var->varattno == InvalidAttrNumber)
810                                         elog(ERROR, "Relation \"%s\" has no column \"%s\"",
811                                                  get_rel_name(context->new_relid), attname);
812                                 pfree(attname);
813                         }
814                 }
815                 return (Node *) var;
816         }
817         if (IsA(node, RangeTblRef))
818         {
819                 RangeTblRef *rtr = (RangeTblRef *) copyObject(node);
820
821                 if (rtr->rtindex == context->old_rt_index)
822                         rtr->rtindex = context->new_rt_index;
823                 return (Node *) rtr;
824         }
825         if (IsA(node, JoinExpr))
826         {
827                 /* Copy the JoinExpr node with correct mutation of subnodes */
828                 JoinExpr   *j;
829
830                 j = (JoinExpr *) expression_tree_mutator(node,
831                                                                                   adjust_inherited_attrs_mutator,
832                                                                                                  (void *) context);
833                 /* now fix JoinExpr's rtindex */
834                 if (j->rtindex == context->old_rt_index)
835                         j->rtindex = context->new_rt_index;
836                 return (Node *) j;
837         }
838
839         /*
840          * We have to process RestrictInfo nodes specially: we do NOT want to
841          * copy the original subclauseindices list, since the new rel may have
842          * different indices.  The list will be rebuilt during later planning.
843          */
844         if (IsA(node, RestrictInfo))
845         {
846                 RestrictInfo *oldinfo = (RestrictInfo *) node;
847                 RestrictInfo *newinfo = makeNode(RestrictInfo);
848
849                 /* Copy all flat-copiable fields */
850                 memcpy(newinfo, oldinfo, sizeof(RestrictInfo));
851
852                 newinfo->clause = (Expr *)
853                         adjust_inherited_attrs_mutator((Node *) oldinfo->clause, context);
854
855                 newinfo->subclauseindices = NIL;
856                 newinfo->eval_cost = -1;        /* reset these too */
857                 newinfo->this_selec = -1;
858                 newinfo->left_pathkey = NIL;    /* and these */
859                 newinfo->right_pathkey = NIL;
860                 newinfo->left_mergescansel = -1;
861                 newinfo->right_mergescansel = -1;
862                 newinfo->left_bucketsize = -1;
863                 newinfo->right_bucketsize = -1;
864
865                 return (Node *) newinfo;
866         }
867
868         /*
869          * NOTE: we do not need to recurse into sublinks, because they should
870          * already have been converted to subplans before we see them.
871          */
872
873         /*
874          * BUT: although we don't need to recurse into subplans, we do need to
875          * make sure that they are copied, not just referenced as
876          * expression_tree_mutator will do by default.  Otherwise we'll have
877          * the same subplan node referenced from each arm of the inheritance
878          * APPEND plan, which will cause trouble in the executor.  This is a
879          * kluge that should go away when we redesign querytrees.
880          */
881         if (is_subplan(node))
882         {
883                 SubPlan *subplan;
884
885                 /* Copy the node and process subplan args */
886                 node = expression_tree_mutator(node, adjust_inherited_attrs_mutator,
887                                                                            (void *) context);
888                 /* Make sure we have separate copies of subplan and its rtable */
889                 subplan = (SubPlan *) node;
890                 subplan->plan = copyObject(subplan->plan);
891                 subplan->rtable = copyObject(subplan->rtable);
892                 return node;
893         }
894
895         return expression_tree_mutator(node, adjust_inherited_attrs_mutator,
896                                                                    (void *) context);
897 }
898
899 /*
900  * Adjust the targetlist entries of an inherited UPDATE operation
901  *
902  * The expressions have already been fixed, but we have to make sure that
903  * the target resnos match the child table (they may not, in the case of
904  * a column that was added after-the-fact by ALTER TABLE).  In some cases
905  * this can force us to re-order the tlist to preserve resno ordering.
906  * (We do all this work in special cases so that preptlist.c is fast for
907  * the typical case.)
908  *
909  * The given tlist has already been through expression_tree_mutator;
910  * therefore the TargetEntry nodes are fresh copies that it's okay to
911  * scribble on.  But the Resdom nodes have not been copied; make new ones
912  * if we need to change them!
913  *
914  * Note that this is not needed for INSERT because INSERT isn't inheritable.
915  */
916 static List *
917 adjust_inherited_tlist(List *tlist, Oid new_relid)
918 {
919         bool            changed_it = false;
920         List       *tl;
921         List       *new_tlist;
922         bool            more;
923         int                     attrno;
924
925         /* Scan tlist and update resnos to match attnums of new_relid */
926         foreach(tl, tlist)
927         {
928                 TargetEntry *tle = (TargetEntry *) lfirst(tl);
929                 Resdom     *resdom = tle->resdom;
930
931                 if (resdom->resjunk)
932                         continue;                       /* ignore junk items */
933
934                 attrno = get_attnum(new_relid, resdom->resname);
935                 if (attrno == InvalidAttrNumber)
936                         elog(ERROR, "Relation \"%s\" has no column \"%s\"",
937                                  get_rel_name(new_relid), resdom->resname);
938                 if (resdom->resno != attrno)
939                 {
940                         resdom = (Resdom *) copyObject((Node *) resdom);
941                         resdom->resno = attrno;
942                         tle->resdom = resdom;
943                         changed_it = true;
944                 }
945         }
946
947         /*
948          * If we changed anything, re-sort the tlist by resno, and make sure
949          * resjunk entries have resnos above the last real resno.  The sort
950          * algorithm is a bit stupid, but for such a seldom-taken path, small
951          * is probably better than fast.
952          */
953         if (!changed_it)
954                 return tlist;
955
956         new_tlist = NIL;
957         more = true;
958         for (attrno = 1; more; attrno++)
959         {
960                 more = false;
961                 foreach(tl, tlist)
962                 {
963                         TargetEntry *tle = (TargetEntry *) lfirst(tl);
964                         Resdom     *resdom = tle->resdom;
965
966                         if (resdom->resjunk)
967                                 continue;               /* ignore junk items */
968
969                         if (resdom->resno == attrno)
970                                 new_tlist = lappend(new_tlist, tle);
971                         else if (resdom->resno > attrno)
972                                 more = true;
973                 }
974         }
975
976         foreach(tl, tlist)
977         {
978                 TargetEntry *tle = (TargetEntry *) lfirst(tl);
979                 Resdom     *resdom = tle->resdom;
980
981                 if (!resdom->resjunk)
982                         continue;                       /* here, ignore non-junk items */
983
984                 if (resdom->resno != attrno)
985                 {
986                         resdom = (Resdom *) copyObject((Node *) resdom);
987                         resdom->resno = attrno;
988                         tle->resdom = resdom;
989                 }
990                 new_tlist = lappend(new_tlist, tle);
991                 attrno++;
992         }
993
994         return new_tlist;
995 }