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