1 /*-------------------------------------------------------------------------
2  *
3  * appendinfo.c
4  *	  Routines for mapping between append parent(s) and children
5  *
6  * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *	  src/backend/optimizer/path/appendinfo.c
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include "postgres.h"
16 
17 #include "access/htup_details.h"
18 #include "nodes/makefuncs.h"
19 #include "nodes/nodeFuncs.h"
20 #include "optimizer/appendinfo.h"
21 #include "parser/parsetree.h"
22 #include "utils/lsyscache.h"
23 #include "utils/rel.h"
24 #include "utils/syscache.h"
25 
26 
27 typedef struct
28 {
29 	PlannerInfo *root;
30 	int			nappinfos;
31 	AppendRelInfo **appinfos;
32 } adjust_appendrel_attrs_context;
33 
34 static void make_inh_translation_list(Relation oldrelation,
35 									  Relation newrelation,
36 									  Index newvarno,
37 									  AppendRelInfo *appinfo);
38 static Node *adjust_appendrel_attrs_mutator(Node *node,
39 											adjust_appendrel_attrs_context *context);
40 static List *adjust_inherited_tlist(List *tlist,
41 									AppendRelInfo *context);
42 
43 
44 /*
45  * make_append_rel_info
46  *	  Build an AppendRelInfo for the parent-child pair
47  */
48 AppendRelInfo *
49 make_append_rel_info(Relation parentrel, Relation childrel,
50 					 Index parentRTindex, Index childRTindex)
51 {
52 	AppendRelInfo *appinfo = makeNode(AppendRelInfo);
53 
54 	appinfo->parent_relid = parentRTindex;
55 	appinfo->child_relid = childRTindex;
56 	appinfo->parent_reltype = parentrel->rd_rel->reltype;
57 	appinfo->child_reltype = childrel->rd_rel->reltype;
58 	make_inh_translation_list(parentrel, childrel, childRTindex, appinfo);
59 	appinfo->parent_reloid = RelationGetRelid(parentrel);
60 
61 	return appinfo;
62 }
63 
64 /*
65  * make_inh_translation_list
66  *	  Build the list of translations from parent Vars to child Vars for
67  *	  an inheritance child, as well as a reverse-translation array.
68  *
69  * The reverse-translation array has an entry for each child relation
70  * column, which is either the 1-based index of the corresponding parent
71  * column, or 0 if there's no match (that happens for dropped child columns,
72  * as well as child columns beyond those of the parent, which are allowed in
73  * traditional inheritance though not partitioning).
74  *
75  * For paranoia's sake, we match type/collation as well as attribute name.
76  */
77 static void
78 make_inh_translation_list(Relation oldrelation, Relation newrelation,
79 						  Index newvarno,
80 						  AppendRelInfo *appinfo)
81 {
82 	List	   *vars = NIL;
83 	AttrNumber *pcolnos;
84 	TupleDesc	old_tupdesc = RelationGetDescr(oldrelation);
85 	TupleDesc	new_tupdesc = RelationGetDescr(newrelation);
86 	Oid			new_relid = RelationGetRelid(newrelation);
87 	int			oldnatts = old_tupdesc->natts;
88 	int			newnatts = new_tupdesc->natts;
89 	int			old_attno;
90 	int			new_attno = 0;
91 
92 	/* Initialize reverse-translation array with all entries zero */
93 	appinfo->num_child_cols = newnatts;
94 	appinfo->parent_colnos = pcolnos =
95 		(AttrNumber *) palloc0(newnatts * sizeof(AttrNumber));
96 
97 	for (old_attno = 0; old_attno < oldnatts; old_attno++)
98 	{
99 		Form_pg_attribute att;
100 		char	   *attname;
101 		Oid			atttypid;
102 		int32		atttypmod;
103 		Oid			attcollation;
104 
105 		att = TupleDescAttr(old_tupdesc, old_attno);
106 		if (att->attisdropped)
107 		{
108 			/* Just put NULL into this list entry */
109 			vars = lappend(vars, NULL);
110 			continue;
111 		}
112 		attname = NameStr(att->attname);
113 		atttypid = att->atttypid;
114 		atttypmod = att->atttypmod;
115 		attcollation = att->attcollation;
116 
117 		/*
118 		 * When we are generating the "translation list" for the parent table
119 		 * of an inheritance set, no need to search for matches.
120 		 */
121 		if (oldrelation == newrelation)
122 		{
123 			vars = lappend(vars, makeVar(newvarno,
124 										 (AttrNumber) (old_attno + 1),
125 										 atttypid,
126 										 atttypmod,
127 										 attcollation,
128 										 0));
129 			pcolnos[old_attno] = old_attno + 1;
130 			continue;
131 		}
132 
133 		/*
134 		 * Otherwise we have to search for the matching column by name.
135 		 * There's no guarantee it'll have the same column position, because
136 		 * of cases like ALTER TABLE ADD COLUMN and multiple inheritance.
137 		 * However, in simple cases, the relative order of columns is mostly
138 		 * the same in both relations, so try the column of newrelation that
139 		 * follows immediately after the one that we just found, and if that
140 		 * fails, let syscache handle it.
141 		 */
142 		if (new_attno >= newnatts ||
143 			(att = TupleDescAttr(new_tupdesc, new_attno))->attisdropped ||
144 			strcmp(attname, NameStr(att->attname)) != 0)
145 		{
146 			HeapTuple	newtup;
147 
148 			newtup = SearchSysCacheAttName(new_relid, attname);
149 			if (!HeapTupleIsValid(newtup))
150 				elog(ERROR, "could not find inherited attribute \"%s\" of relation \"%s\"",
151 					 attname, RelationGetRelationName(newrelation));
152 			new_attno = ((Form_pg_attribute) GETSTRUCT(newtup))->attnum - 1;
153 			Assert(new_attno >= 0 && new_attno < newnatts);
154 			ReleaseSysCache(newtup);
155 
156 			att = TupleDescAttr(new_tupdesc, new_attno);
157 		}
158 
159 		/* Found it, check type and collation match */
160 		if (atttypid != att->atttypid || atttypmod != att->atttypmod)
161 			elog(ERROR, "attribute \"%s\" of relation \"%s\" does not match parent's type",
162 				 attname, RelationGetRelationName(newrelation));
163 		if (attcollation != att->attcollation)
164 			elog(ERROR, "attribute \"%s\" of relation \"%s\" does not match parent's collation",
165 				 attname, RelationGetRelationName(newrelation));
166 
167 		vars = lappend(vars, makeVar(newvarno,
168 									 (AttrNumber) (new_attno + 1),
169 									 atttypid,
170 									 atttypmod,
171 									 attcollation,
172 									 0));
173 		pcolnos[new_attno] = old_attno + 1;
174 		new_attno++;
175 	}
176 
177 	appinfo->translated_vars = vars;
178 }
179 
180 /*
181  * adjust_appendrel_attrs
182  *	  Copy the specified query or expression and translate Vars referring to a
183  *	  parent rel to refer to the corresponding child rel instead.  We also
184  *	  update rtindexes appearing outside Vars, such as resultRelation and
185  *	  jointree relids.
186  *
187  * Note: this is only applied after conversion of sublinks to subplans,
188  * so we don't need to cope with recursion into sub-queries.
189  *
190  * Note: this is not hugely different from what pullup_replace_vars() does;
191  * maybe we should try to fold the two routines together.
192  */
193 Node *
194 adjust_appendrel_attrs(PlannerInfo *root, Node *node, int nappinfos,
195 					   AppendRelInfo **appinfos)
196 {
197 	Node	   *result;
198 	adjust_appendrel_attrs_context context;
199 
200 	context.root = root;
201 	context.nappinfos = nappinfos;
202 	context.appinfos = appinfos;
203 
204 	/* If there's nothing to adjust, don't call this function. */
205 	Assert(nappinfos >= 1 && appinfos != NULL);
206 
207 	/*
208 	 * Must be prepared to start with a Query or a bare expression tree.
209 	 */
210 	if (node && IsA(node, Query))
211 	{
212 		Query	   *newnode;
213 		int			cnt;
214 
215 		newnode = query_tree_mutator((Query *) node,
216 									 adjust_appendrel_attrs_mutator,
217 									 (void *) &context,
218 									 QTW_IGNORE_RC_SUBQUERIES);
219 		for (cnt = 0; cnt < nappinfos; cnt++)
220 		{
221 			AppendRelInfo *appinfo = appinfos[cnt];
222 
223 			if (newnode->resultRelation == appinfo->parent_relid)
224 			{
225 				newnode->resultRelation = appinfo->child_relid;
226 				/* Fix tlist resnos too, if it's inherited UPDATE */
227 				if (newnode->commandType == CMD_UPDATE)
228 					newnode->targetList =
229 						adjust_inherited_tlist(newnode->targetList,
230 											   appinfo);
231 				break;
232 			}
233 		}
234 
235 		result = (Node *) newnode;
236 	}
237 	else
238 		result = adjust_appendrel_attrs_mutator(node, &context);
239 
240 	return result;
241 }
242 
243 static Node *
244 adjust_appendrel_attrs_mutator(Node *node,
245 							   adjust_appendrel_attrs_context *context)
246 {
247 	AppendRelInfo **appinfos = context->appinfos;
248 	int			nappinfos = context->nappinfos;
249 	int			cnt;
250 
251 	if (node == NULL)
252 		return NULL;
253 	if (IsA(node, Var))
254 	{
255 		Var		   *var = (Var *) copyObject(node);
256 		AppendRelInfo *appinfo = NULL;
257 
258 		if (var->varlevelsup != 0)
259 			return (Node *) var;	/* no changes needed */
260 
261 		for (cnt = 0; cnt < nappinfos; cnt++)
262 		{
263 			if (var->varno == appinfos[cnt]->parent_relid)
264 			{
265 				appinfo = appinfos[cnt];
266 				break;
267 			}
268 		}
269 
270 		if (appinfo)
271 		{
272 			var->varno = appinfo->child_relid;
273 			/* it's now a generated Var, so drop any syntactic labeling */
274 			var->varnosyn = 0;
275 			var->varattnosyn = 0;
276 			if (var->varattno > 0)
277 			{
278 				Node	   *newnode;
279 
280 				if (var->varattno > list_length(appinfo->translated_vars))
281 					elog(ERROR, "attribute %d of relation \"%s\" does not exist",
282 						 var->varattno, get_rel_name(appinfo->parent_reloid));
283 				newnode = copyObject(list_nth(appinfo->translated_vars,
284 											  var->varattno - 1));
285 				if (newnode == NULL)
286 					elog(ERROR, "attribute %d of relation \"%s\" does not exist",
287 						 var->varattno, get_rel_name(appinfo->parent_reloid));
288 				return newnode;
289 			}
290 			else if (var->varattno == 0)
291 			{
292 				/*
293 				 * Whole-row Var: if we are dealing with named rowtypes, we
294 				 * can use a whole-row Var for the child table plus a coercion
295 				 * step to convert the tuple layout to the parent's rowtype.
296 				 * Otherwise we have to generate a RowExpr.
297 				 */
298 				if (OidIsValid(appinfo->child_reltype))
299 				{
300 					Assert(var->vartype == appinfo->parent_reltype);
301 					if (appinfo->parent_reltype != appinfo->child_reltype)
302 					{
303 						ConvertRowtypeExpr *r = makeNode(ConvertRowtypeExpr);
304 
305 						r->arg = (Expr *) var;
306 						r->resulttype = appinfo->parent_reltype;
307 						r->convertformat = COERCE_IMPLICIT_CAST;
308 						r->location = -1;
309 						/* Make sure the Var node has the right type ID, too */
310 						var->vartype = appinfo->child_reltype;
311 						return (Node *) r;
312 					}
313 				}
314 				else
315 				{
316 					/*
317 					 * Build a RowExpr containing the translated variables.
318 					 *
319 					 * In practice var->vartype will always be RECORDOID here,
320 					 * so we need to come up with some suitable column names.
321 					 * We use the parent RTE's column names.
322 					 *
323 					 * Note: we can't get here for inheritance cases, so there
324 					 * is no need to worry that translated_vars might contain
325 					 * some dummy NULLs.
326 					 */
327 					RowExpr    *rowexpr;
328 					List	   *fields;
329 					RangeTblEntry *rte;
330 
331 					rte = rt_fetch(appinfo->parent_relid,
332 								   context->root->parse->rtable);
333 					fields = copyObject(appinfo->translated_vars);
334 					rowexpr = makeNode(RowExpr);
335 					rowexpr->args = fields;
336 					rowexpr->row_typeid = var->vartype;
337 					rowexpr->row_format = COERCE_IMPLICIT_CAST;
338 					rowexpr->colnames = copyObject(rte->eref->colnames);
339 					rowexpr->location = -1;
340 
341 					return (Node *) rowexpr;
342 				}
343 			}
344 			/* system attributes don't need any other translation */
345 		}
346 		return (Node *) var;
347 	}
348 	if (IsA(node, CurrentOfExpr))
349 	{
350 		CurrentOfExpr *cexpr = (CurrentOfExpr *) copyObject(node);
351 
352 		for (cnt = 0; cnt < nappinfos; cnt++)
353 		{
354 			AppendRelInfo *appinfo = appinfos[cnt];
355 
356 			if (cexpr->cvarno == appinfo->parent_relid)
357 			{
358 				cexpr->cvarno = appinfo->child_relid;
359 				break;
360 			}
361 		}
362 		return (Node *) cexpr;
363 	}
364 	if (IsA(node, RangeTblRef))
365 	{
366 		RangeTblRef *rtr = (RangeTblRef *) copyObject(node);
367 
368 		for (cnt = 0; cnt < nappinfos; cnt++)
369 		{
370 			AppendRelInfo *appinfo = appinfos[cnt];
371 
372 			if (rtr->rtindex == appinfo->parent_relid)
373 			{
374 				rtr->rtindex = appinfo->child_relid;
375 				break;
376 			}
377 		}
378 		return (Node *) rtr;
379 	}
380 	if (IsA(node, JoinExpr))
381 	{
382 		/* Copy the JoinExpr node with correct mutation of subnodes */
383 		JoinExpr   *j;
384 		AppendRelInfo *appinfo;
385 
386 		j = (JoinExpr *) expression_tree_mutator(node,
387 												 adjust_appendrel_attrs_mutator,
388 												 (void *) context);
389 		/* now fix JoinExpr's rtindex (probably never happens) */
390 		for (cnt = 0; cnt < nappinfos; cnt++)
391 		{
392 			appinfo = appinfos[cnt];
393 
394 			if (j->rtindex == appinfo->parent_relid)
395 			{
396 				j->rtindex = appinfo->child_relid;
397 				break;
398 			}
399 		}
400 		return (Node *) j;
401 	}
402 	if (IsA(node, PlaceHolderVar))
403 	{
404 		/* Copy the PlaceHolderVar node with correct mutation of subnodes */
405 		PlaceHolderVar *phv;
406 
407 		phv = (PlaceHolderVar *) expression_tree_mutator(node,
408 														 adjust_appendrel_attrs_mutator,
409 														 (void *) context);
410 		/* now fix PlaceHolderVar's relid sets */
411 		if (phv->phlevelsup == 0)
412 			phv->phrels = adjust_child_relids(phv->phrels, context->nappinfos,
413 											  context->appinfos);
414 		return (Node *) phv;
415 	}
416 	/* Shouldn't need to handle planner auxiliary nodes here */
417 	Assert(!IsA(node, SpecialJoinInfo));
418 	Assert(!IsA(node, AppendRelInfo));
419 	Assert(!IsA(node, PlaceHolderInfo));
420 	Assert(!IsA(node, MinMaxAggInfo));
421 
422 	/*
423 	 * We have to process RestrictInfo nodes specially.  (Note: although
424 	 * set_append_rel_pathlist will hide RestrictInfos in the parent's
425 	 * baserestrictinfo list from us, it doesn't hide those in joininfo.)
426 	 */
427 	if (IsA(node, RestrictInfo))
428 	{
429 		RestrictInfo *oldinfo = (RestrictInfo *) node;
430 		RestrictInfo *newinfo = makeNode(RestrictInfo);
431 
432 		/* Copy all flat-copiable fields */
433 		memcpy(newinfo, oldinfo, sizeof(RestrictInfo));
434 
435 		/* Recursively fix the clause itself */
436 		newinfo->clause = (Expr *)
437 			adjust_appendrel_attrs_mutator((Node *) oldinfo->clause, context);
438 
439 		/* and the modified version, if an OR clause */
440 		newinfo->orclause = (Expr *)
441 			adjust_appendrel_attrs_mutator((Node *) oldinfo->orclause, context);
442 
443 		/* adjust relid sets too */
444 		newinfo->clause_relids = adjust_child_relids(oldinfo->clause_relids,
445 													 context->nappinfos,
446 													 context->appinfos);
447 		newinfo->required_relids = adjust_child_relids(oldinfo->required_relids,
448 													   context->nappinfos,
449 													   context->appinfos);
450 		newinfo->outer_relids = adjust_child_relids(oldinfo->outer_relids,
451 													context->nappinfos,
452 													context->appinfos);
453 		newinfo->nullable_relids = adjust_child_relids(oldinfo->nullable_relids,
454 													   context->nappinfos,
455 													   context->appinfos);
456 		newinfo->left_relids = adjust_child_relids(oldinfo->left_relids,
457 												   context->nappinfos,
458 												   context->appinfos);
459 		newinfo->right_relids = adjust_child_relids(oldinfo->right_relids,
460 													context->nappinfos,
461 													context->appinfos);
462 
463 		/*
464 		 * Reset cached derivative fields, since these might need to have
465 		 * different values when considering the child relation.  Note we
466 		 * don't reset left_ec/right_ec: each child variable is implicitly
467 		 * equivalent to its parent, so still a member of the same EC if any.
468 		 */
469 		newinfo->eval_cost.startup = -1;
470 		newinfo->norm_selec = -1;
471 		newinfo->outer_selec = -1;
472 		newinfo->left_em = NULL;
473 		newinfo->right_em = NULL;
474 		newinfo->scansel_cache = NIL;
475 		newinfo->left_bucketsize = -1;
476 		newinfo->right_bucketsize = -1;
477 		newinfo->left_mcvfreq = -1;
478 		newinfo->right_mcvfreq = -1;
479 
480 		return (Node *) newinfo;
481 	}
482 
483 	/*
484 	 * NOTE: we do not need to recurse into sublinks, because they should
485 	 * already have been converted to subplans before we see them.
486 	 */
487 	Assert(!IsA(node, SubLink));
488 	Assert(!IsA(node, Query));
489 
490 	return expression_tree_mutator(node, adjust_appendrel_attrs_mutator,
491 								   (void *) context);
492 }
493 
494 /*
495  * adjust_appendrel_attrs_multilevel
496  *	  Apply Var translations from a toplevel appendrel parent down to a child.
497  *
498  * In some cases we need to translate expressions referencing a parent relation
499  * to reference an appendrel child that's multiple levels removed from it.
500  */
501 Node *
502 adjust_appendrel_attrs_multilevel(PlannerInfo *root, Node *node,
503 								  Relids child_relids,
504 								  Relids top_parent_relids)
505 {
506 	AppendRelInfo **appinfos;
507 	Bitmapset  *parent_relids = NULL;
508 	int			nappinfos;
509 	int			cnt;
510 
511 	Assert(bms_num_members(child_relids) == bms_num_members(top_parent_relids));
512 
513 	appinfos = find_appinfos_by_relids(root, child_relids, &nappinfos);
514 
515 	/* Construct relids set for the immediate parent of given child. */
516 	for (cnt = 0; cnt < nappinfos; cnt++)
517 	{
518 		AppendRelInfo *appinfo = appinfos[cnt];
519 
520 		parent_relids = bms_add_member(parent_relids, appinfo->parent_relid);
521 	}
522 
523 	/* Recurse if immediate parent is not the top parent. */
524 	if (!bms_equal(parent_relids, top_parent_relids))
525 		node = adjust_appendrel_attrs_multilevel(root, node, parent_relids,
526 												 top_parent_relids);
527 
528 	/* Now translate for this child */
529 	node = adjust_appendrel_attrs(root, node, nappinfos, appinfos);
530 
531 	pfree(appinfos);
532 
533 	return node;
534 }
535 
536 /*
537  * Substitute child relids for parent relids in a Relid set.  The array of
538  * appinfos specifies the substitutions to be performed.
539  */
540 Relids
541 adjust_child_relids(Relids relids, int nappinfos, AppendRelInfo **appinfos)
542 {
543 	Bitmapset  *result = NULL;
544 	int			cnt;
545 
546 	for (cnt = 0; cnt < nappinfos; cnt++)
547 	{
548 		AppendRelInfo *appinfo = appinfos[cnt];
549 
550 		/* Remove parent, add child */
551 		if (bms_is_member(appinfo->parent_relid, relids))
552 		{
553 			/* Make a copy if we are changing the set. */
554 			if (!result)
555 				result = bms_copy(relids);
556 
557 			result = bms_del_member(result, appinfo->parent_relid);
558 			result = bms_add_member(result, appinfo->child_relid);
559 		}
560 	}
561 
562 	/* If we made any changes, return the modified copy. */
563 	if (result)
564 		return result;
565 
566 	/* Otherwise, return the original set without modification. */
567 	return relids;
568 }
569 
570 /*
571  * Replace any relid present in top_parent_relids with its child in
572  * child_relids. Members of child_relids can be multiple levels below top
573  * parent in the partition hierarchy.
574  */
575 Relids
576 adjust_child_relids_multilevel(PlannerInfo *root, Relids relids,
577 							   Relids child_relids, Relids top_parent_relids)
578 {
579 	AppendRelInfo **appinfos;
580 	int			nappinfos;
581 	Relids		parent_relids = NULL;
582 	Relids		result;
583 	Relids		tmp_result = NULL;
584 	int			cnt;
585 
586 	/*
587 	 * If the given relids set doesn't contain any of the top parent relids,
588 	 * it will remain unchanged.
589 	 */
590 	if (!bms_overlap(relids, top_parent_relids))
591 		return relids;
592 
593 	appinfos = find_appinfos_by_relids(root, child_relids, &nappinfos);
594 
595 	/* Construct relids set for the immediate parent of the given child. */
596 	for (cnt = 0; cnt < nappinfos; cnt++)
597 	{
598 		AppendRelInfo *appinfo = appinfos[cnt];
599 
600 		parent_relids = bms_add_member(parent_relids, appinfo->parent_relid);
601 	}
602 
603 	/* Recurse if immediate parent is not the top parent. */
604 	if (!bms_equal(parent_relids, top_parent_relids))
605 	{
606 		tmp_result = adjust_child_relids_multilevel(root, relids,
607 													parent_relids,
608 													top_parent_relids);
609 		relids = tmp_result;
610 	}
611 
612 	result = adjust_child_relids(relids, nappinfos, appinfos);
613 
614 	/* Free memory consumed by any intermediate result. */
615 	if (tmp_result)
616 		bms_free(tmp_result);
617 	bms_free(parent_relids);
618 	pfree(appinfos);
619 
620 	return result;
621 }
622 
623 /*
624  * Adjust the targetlist entries of an inherited UPDATE operation
625  *
626  * The expressions have already been fixed, but we have to make sure that
627  * the target resnos match the child table (they may not, in the case of
628  * a column that was added after-the-fact by ALTER TABLE).  In some cases
629  * this can force us to re-order the tlist to preserve resno ordering.
630  * (We do all this work in special cases so that preptlist.c is fast for
631  * the typical case.)
632  *
633  * The given tlist has already been through expression_tree_mutator;
634  * therefore the TargetEntry nodes are fresh copies that it's okay to
635  * scribble on.
636  *
637  * Note that this is not needed for INSERT because INSERT isn't inheritable.
638  */
639 static List *
640 adjust_inherited_tlist(List *tlist, AppendRelInfo *context)
641 {
642 	bool		changed_it = false;
643 	ListCell   *tl;
644 	List	   *new_tlist;
645 	bool		more;
646 	int			attrno;
647 
648 	/* This should only happen for an inheritance case, not UNION ALL */
649 	Assert(OidIsValid(context->parent_reloid));
650 
651 	/* Scan tlist and update resnos to match attnums of child rel */
652 	foreach(tl, tlist)
653 	{
654 		TargetEntry *tle = (TargetEntry *) lfirst(tl);
655 		Var		   *childvar;
656 
657 		if (tle->resjunk)
658 			continue;			/* ignore junk items */
659 
660 		/* Look up the translation of this column: it must be a Var */
661 		if (tle->resno <= 0 ||
662 			tle->resno > list_length(context->translated_vars))
663 			elog(ERROR, "attribute %d of relation \"%s\" does not exist",
664 				 tle->resno, get_rel_name(context->parent_reloid));
665 		childvar = (Var *) list_nth(context->translated_vars, tle->resno - 1);
666 		if (childvar == NULL || !IsA(childvar, Var))
667 			elog(ERROR, "attribute %d of relation \"%s\" does not exist",
668 				 tle->resno, get_rel_name(context->parent_reloid));
669 
670 		if (tle->resno != childvar->varattno)
671 		{
672 			tle->resno = childvar->varattno;
673 			changed_it = true;
674 		}
675 	}
676 
677 	/*
678 	 * If we changed anything, re-sort the tlist by resno, and make sure
679 	 * resjunk entries have resnos above the last real resno.  The sort
680 	 * algorithm is a bit stupid, but for such a seldom-taken path, small is
681 	 * probably better than fast.
682 	 */
683 	if (!changed_it)
684 		return tlist;
685 
686 	new_tlist = NIL;
687 	more = true;
688 	for (attrno = 1; more; attrno++)
689 	{
690 		more = false;
691 		foreach(tl, tlist)
692 		{
693 			TargetEntry *tle = (TargetEntry *) lfirst(tl);
694 
695 			if (tle->resjunk)
696 				continue;		/* ignore junk items */
697 
698 			if (tle->resno == attrno)
699 				new_tlist = lappend(new_tlist, tle);
700 			else if (tle->resno > attrno)
701 				more = true;
702 		}
703 	}
704 
705 	foreach(tl, tlist)
706 	{
707 		TargetEntry *tle = (TargetEntry *) lfirst(tl);
708 
709 		if (!tle->resjunk)
710 			continue;			/* here, ignore non-junk items */
711 
712 		tle->resno = attrno;
713 		new_tlist = lappend(new_tlist, tle);
714 		attrno++;
715 	}
716 
717 	return new_tlist;
718 }
719 
720 /*
721  * find_appinfos_by_relids
722  * 		Find AppendRelInfo structures for all relations specified by relids.
723  *
724  * The AppendRelInfos are returned in an array, which can be pfree'd by the
725  * caller. *nappinfos is set to the number of entries in the array.
726  */
727 AppendRelInfo **
728 find_appinfos_by_relids(PlannerInfo *root, Relids relids, int *nappinfos)
729 {
730 	AppendRelInfo **appinfos;
731 	int			cnt = 0;
732 	int			i;
733 
734 	*nappinfos = bms_num_members(relids);
735 	appinfos = (AppendRelInfo **) palloc(sizeof(AppendRelInfo *) * *nappinfos);
736 
737 	i = -1;
738 	while ((i = bms_next_member(relids, i)) >= 0)
739 	{
740 		AppendRelInfo *appinfo = root->append_rel_array[i];
741 
742 		if (!appinfo)
743 			elog(ERROR, "child rel %d not found in append_rel_array", i);
744 
745 		appinfos[cnt++] = appinfo;
746 	}
747 	return appinfos;
748 }
749