prepunion.c 22.1 KB
Newer Older
1 2
/*-------------------------------------------------------------------------
 *
3
 * prepunion.c
4 5 6 7
 *	  Routines to plan set-operation queries.  The filename is a leftover
 *	  from a time when only UNIONs were implemented.
 *
 * 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 10
 * to the processing of UNION queries, but it's still here.
 *
11
 *
12
 * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
Bruce Momjian's avatar
Add:  
Bruce Momjian committed
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.66 2001/08/14 17:12:57 tgl Exp $
18 19 20 21 22
 *
 *-------------------------------------------------------------------------
 */
#include "postgres.h"

23 24 25 26
#include <sys/types.h>

#include "catalog/pg_type.h"
#include "nodes/makefuncs.h"
27
#include "optimizer/clauses.h"
28
#include "optimizer/plancat.h"
29
#include "optimizer/planmain.h"
Bruce Momjian's avatar
Bruce Momjian committed
30 31
#include "optimizer/planner.h"
#include "optimizer/prep.h"
32
#include "optimizer/tlist.h"
Bruce Momjian's avatar
Bruce Momjian committed
33
#include "parser/parse_clause.h"
34
#include "parser/parse_coerce.h"
Bruce Momjian's avatar
Bruce Momjian committed
35 36
#include "parser/parsetree.h"
#include "utils/lsyscache.h"
37

38 39 40 41 42 43
/* macros borrowed from expression_tree_mutator */

#define FLATCOPY(newnode, node, nodetype)  \
	( (newnode) = makeNode(nodetype), \
	  memcpy((newnode), (node), sizeof(nodetype)) )

44 45
typedef struct
{
46 47
	Index		old_rt_index;
	Index		new_rt_index;
48 49
	Oid			old_relid;
	Oid			new_relid;
50
} adjust_inherited_attrs_context;
51

52
static Plan *recurse_set_operations(Node *setOp, Query *parse,
53 54
					   List *colTypes, bool junkOK,
					   int flag, List *refnames_tlist);
55
static Plan *generate_union_plan(SetOperationStmt *op, Query *parse,
56
					List *refnames_tlist);
57
static Plan *generate_nonunion_plan(SetOperationStmt *op, Query *parse,
58
					   List *refnames_tlist);
59
static List *recurse_union_children(Node *setOp, Query *parse,
60 61
					   SetOperationStmt *top_union,
					   List *refnames_tlist);
62
static List *generate_setop_tlist(List *colTypes, int flag,
63 64 65
					 bool hack_constants,
					 List *input_tlist,
					 List *refnames_tlist);
66
static bool tlist_same_datatypes(List *tlist, List *colTypes, bool junkOK);
67
static Node *adjust_inherited_attrs_mutator(Node *node,
68
							   adjust_inherited_attrs_context *context);
69 70


71
/*
72
 * plan_set_operations
73
 *
74
 *	  Plans the queries for a tree of set operations (UNION/INTERSECT/EXCEPT)
75
 *
76
 * This routine only deals with the setOperations tree of the given query.
77 78
 * Any top-level ORDER BY requested in parse->sortClause will be added
 * when we return to grouping_planner.
79
 */
80
Plan *
81
plan_set_operations(Query *parse)
82
{
83 84 85 86 87 88 89 90 91
	SetOperationStmt *topop = (SetOperationStmt *) parse->setOperations;
	Node	   *node;
	Query	   *leftmostQuery;

	Assert(topop && IsA(topop, SetOperationStmt));

	/*
	 * Find the leftmost component Query.  We need to use its column names
	 * for all generated tlists (else SELECT INTO won't work right).
92
	 */
93 94 95 96 97 98 99
	node = topop->larg;
	while (node && IsA(node, SetOperationStmt))
		node = ((SetOperationStmt *) node)->larg;
	Assert(node && IsA(node, RangeTblRef));
	leftmostQuery = rt_fetch(((RangeTblRef *) node)->rtindex,
							 parse->rtable)->subquery;
	Assert(leftmostQuery != NULL);
100

101
	/*
102 103 104 105
	 * Recurse on setOperations tree to generate plans for set ops. The
	 * final output plan should have just the column types shown as the
	 * output from the top-level node, plus possibly a resjunk working
	 * column (we can rely on upper-level nodes to deal with that).
106 107
	 */
	return recurse_set_operations((Node *) topop, parse,
108
								  topop->colTypes, true, -1,
109 110 111 112 113 114 115 116
								  leftmostQuery->targetList);
}

/*
 * recurse_set_operations
 *	  Recursively handle one step in a tree of set operations
 *
 * colTypes: integer list of type OIDs of expected output columns
117
 * junkOK: if true, child resjunk columns may be left in the result
118 119 120 121 122
 * flag: if >= 0, add a resjunk output column indicating value of flag
 * refnames_tlist: targetlist to take column names from
 */
static Plan *
recurse_set_operations(Node *setOp, Query *parse,
123 124
					   List *colTypes, bool junkOK,
					   int flag, List *refnames_tlist)
125 126
{
	if (IsA(setOp, RangeTblRef))
127
	{
128 129
		RangeTblRef *rtr = (RangeTblRef *) setOp;
		RangeTblEntry *rte = rt_fetch(rtr->rtindex, parse->rtable);
130 131 132
		Query	   *subquery = rte->subquery;
		Plan	   *subplan,
				   *plan;
133

134
		Assert(subquery != NULL);
135

136 137 138 139 140
		/*
		 * Generate plan for primitive subquery
		 */
		subplan = subquery_planner(subquery,
								   -1.0 /* default case */ );
141

142 143 144 145
		/*
		 * Add a SubqueryScan with the caller-requested targetlist
		 */
		plan = (Plan *)
146
			make_subqueryscan(generate_setop_tlist(colTypes, flag, true,
147 148 149 150 151 152
												   subplan->targetlist,
												   refnames_tlist),
							  NIL,
							  rtr->rtindex,
							  subplan);
		return plan;
153
	}
154
	else if (IsA(setOp, SetOperationStmt))
155
	{
156
		SetOperationStmt *op = (SetOperationStmt *) setOp;
157
		Plan	   *plan;
158

159 160 161 162 163
		/* UNIONs are much different from INTERSECT/EXCEPT */
		if (op->op == SETOP_UNION)
			plan = generate_union_plan(op, parse, refnames_tlist);
		else
			plan = generate_nonunion_plan(op, parse, refnames_tlist);
164

165 166 167 168 169 170
		/*
		 * If necessary, add a Result node to project the caller-requested
		 * output columns.
		 *
		 * XXX you don't really want to know about this: setrefs.c will apply
		 * replace_vars_with_subplan_refs() to the Result node's tlist.
171 172 173 174 175 176 177
		 * This would fail if the input plan's non-resjunk tlist entries
		 * were not all simple Vars equal() to the referencing Vars
		 * generated by generate_setop_tlist().  However, since the input
		 * plan was generated by generate_union_plan() or
		 * generate_nonunion_plan(), the referencing Vars will equal the
		 * tlist entries they reference. Ugly but I don't feel like making
		 * that code more general right now.
178
		 */
179
		if (flag >= 0 ||
180
			!tlist_same_datatypes(plan->targetlist, colTypes, junkOK))
181
		{
182
			plan = (Plan *)
183
				make_result(generate_setop_tlist(colTypes, flag, false,
184 185 186 187
												 plan->targetlist,
												 refnames_tlist),
							NULL,
							plan);
188
		}
189
		return plan;
190 191 192
	}
	else
	{
193 194 195 196 197
		elog(ERROR, "recurse_set_operations: unexpected node %d",
			 (int) nodeTag(setOp));
		return NULL;			/* keep compiler quiet */
	}
}
198

199 200 201 202 203 204 205
/*
 * Generate plan for a UNION or UNION ALL node
 */
static Plan *
generate_union_plan(SetOperationStmt *op, Query *parse,
					List *refnames_tlist)
{
206 207
	List	   *planlist;
	Plan	   *plan;
208 209 210 211 212 213 214 215 216 217 218

	/*
	 * If any of my children are identical UNION nodes (same op, all-flag,
	 * and colTypes) then they can be merged into this node so that we
	 * generate only one Append and Sort for the lot.  Recurse to find
	 * such nodes and compute their children's plans.
	 */
	planlist = nconc(recurse_union_children(op->larg, parse,
											op, refnames_tlist),
					 recurse_union_children(op->rarg, parse,
											op, refnames_tlist));
219

220 221 222
	/*
	 * Append the child results together.
	 *
223 224 225
	 * The tlist for an Append plan isn't important as far as the Append is
	 * concerned, but we must make it look real anyway for the benefit of
	 * the next plan level up.
226 227 228
	 */
	plan = (Plan *)
		make_append(planlist,
229
					false,
230
					generate_setop_tlist(op->colTypes, -1, false,
231 232 233
								 ((Plan *) lfirst(planlist))->targetlist,
										 refnames_tlist));

234
	/*
235 236
	 * For UNION ALL, we just need the Append plan.  For UNION, need to
	 * add Sort and Unique nodes to produce unique output.
237
	 */
238
	if (!op->all)
239
	{
240 241
		List	   *tlist,
				   *sortList;
242

243 244
		tlist = new_unsorted_tlist(plan->targetlist);
		sortList = addAllTargetsToSortList(NIL, tlist);
245
		plan = make_sortplan(parse, tlist, plan, sortList);
246 247 248 249
		plan = (Plan *) make_unique(tlist, plan, copyObject(sortList));
	}
	return plan;
}
250

251 252 253 254 255 256 257
/*
 * Generate plan for an INTERSECT, INTERSECT ALL, EXCEPT, or EXCEPT ALL node
 */
static Plan *
generate_nonunion_plan(SetOperationStmt *op, Query *parse,
					   List *refnames_tlist)
{
258 259 260 261 262 263
	Plan	   *lplan,
			   *rplan,
			   *plan;
	List	   *tlist,
			   *sortList;
	SetOpCmd	cmd;
264 265 266

	/* Recurse on children, ensuring their outputs are marked */
	lplan = recurse_set_operations(op->larg, parse,
267
								   op->colTypes, false, 0,
268 269
								   refnames_tlist);
	rplan = recurse_set_operations(op->rarg, parse,
270
								   op->colTypes, false, 1,
271
								   refnames_tlist);
272

273 274 275
	/*
	 * Append the child results together.
	 *
276 277
	 * The tlist for an Append plan isn't important as far as the Append is
	 * concerned, but we must make it look real anyway for the benefit of
278 279 280
	 * the next plan level up.  In fact, it has to be real enough that the
	 * flag column is shown as a variable not a constant, else setrefs.c
	 * will get confused.
281 282 283
	 */
	plan = (Plan *)
		make_append(makeList2(lplan, rplan),
284
					false,
285
					generate_setop_tlist(op->colTypes, 2, false,
286 287
										 lplan->targetlist,
										 refnames_tlist));
288

289
	/*
290 291
	 * Sort the child results, then add a SetOp plan node to generate the
	 * correct output.
292 293 294
	 */
	tlist = new_unsorted_tlist(plan->targetlist);
	sortList = addAllTargetsToSortList(NIL, tlist);
295
	plan = make_sortplan(parse, tlist, plan, sortList);
296 297 298 299 300 301 302 303 304 305
	switch (op->op)
	{
		case SETOP_INTERSECT:
			cmd = op->all ? SETOPCMD_INTERSECT_ALL : SETOPCMD_INTERSECT;
			break;
		case SETOP_EXCEPT:
			cmd = op->all ? SETOPCMD_EXCEPT_ALL : SETOPCMD_EXCEPT;
			break;
		default:
			elog(ERROR, "generate_nonunion_plan: bogus operation code");
306
			cmd = SETOPCMD_INTERSECT;	/* keep compiler quiet */
307 308 309
			break;
	}
	plan = (Plan *) make_setop(cmd, tlist, plan, sortList,
310
							   length(op->colTypes) + 1);
311 312
	return plan;
}
313

314 315 316 317 318 319 320 321 322 323 324 325 326 327
/*
 * Pull up children of a UNION node that are identically-propertied UNIONs.
 *
 * NOTE: we can also pull a UNION ALL up into a UNION, since the distinct
 * output rows will be lost anyway.
 */
static List *
recurse_union_children(Node *setOp, Query *parse,
					   SetOperationStmt *top_union,
					   List *refnames_tlist)
{
	if (IsA(setOp, SetOperationStmt))
	{
		SetOperationStmt *op = (SetOperationStmt *) setOp;
328

329 330 331
		if (op->op == top_union->op &&
			(op->all == top_union->all || op->all) &&
			equali(op->colTypes, top_union->colTypes))
332
		{
333 334
			/* Same UNION, so fold children into parent's subplan list */
			return nconc(recurse_union_children(op->larg, parse,
335
											  top_union, refnames_tlist),
336
						 recurse_union_children(op->rarg, parse,
337
											 top_union, refnames_tlist));
338
		}
339
	}
340

341 342 343
	/*
	 * Not same, so plan this child separately.
	 *
344 345 346 347 348 349
	 * Note we disallow any resjunk columns in child results.  This is
	 * necessary since the Append node that implements the union won't do
	 * any projection, and upper levels will get confused if some of our
	 * output tuples have junk and some don't.  This case only arises when
	 * we have an EXCEPT or INTERSECT as child, else there won't be
	 * resjunk anyway.
350
	 */
351
	return makeList1(recurse_set_operations(setOp, parse,
352 353
											top_union->colTypes, false,
											-1, refnames_tlist));
354
}
355

356 357
/*
 * Generate targetlist for a set-operation plan node
358 359 360 361 362 363 364
 *
 * colTypes: column datatypes for non-junk columns
 * flag: -1 if no flag column needed, 0 or 1 to create a const flag column,
 *       2 to create a variable flag column
 * hack_constants: true to copy up constants (see comments in code)
 * input_tlist: targetlist of this node's input node
 * refnames_tlist: targetlist to take column names from
365 366 367
 */
static List *
generate_setop_tlist(List *colTypes, int flag,
368
					 bool hack_constants,
369 370 371 372 373 374 375 376
					 List *input_tlist,
					 List *refnames_tlist)
{
	List	   *tlist = NIL;
	int			resno = 1;
	List	   *i;
	Resdom	   *resdom;
	Node	   *expr;
377

378 379
	foreach(i, colTypes)
	{
380
		Oid			colType = (Oid) lfirsti(i);
381 382 383 384 385 386 387
		TargetEntry *inputtle = (TargetEntry *) lfirst(input_tlist);
		TargetEntry *reftle = (TargetEntry *) lfirst(refnames_tlist);

		Assert(inputtle->resdom->resno == resno);
		Assert(reftle->resdom->resno == resno);
		Assert(!inputtle->resdom->resjunk);
		Assert(!reftle->resdom->resjunk);
388

389
		/*
390 391 392 393 394
		 * Generate columns referencing input columns and having
		 * appropriate data types and column names.  Insert datatype
		 * coercions where necessary.
		 *
		 * HACK: constants in the input's targetlist are copied up as-is
395 396 397 398 399 400
		 * rather than being referenced as subquery outputs.  This is
		 * mainly to ensure that when we try to coerce them to the output
		 * column's datatype, the right things happen for UNKNOWN
		 * constants.  But do this only at the first level of
		 * subquery-scan plans; we don't want phony constants appearing in
		 * the output tlists of upper-level nodes!
401
		 */
402 403 404 405 406
		resdom = makeResdom((AttrNumber) resno++,
							colType,
							-1,
							pstrdup(reftle->resdom->resname),
							false);
407
		if (hack_constants && inputtle->expr && IsA(inputtle->expr, Const))
408 409 410 411 412 413 414 415 416 417 418 419 420 421
			expr = inputtle->expr;
		else
			expr = (Node *) makeVar(0,
									inputtle->resdom->resno,
									inputtle->resdom->restype,
									inputtle->resdom->restypmod,
									0);
		expr = coerce_to_common_type(NULL,
									 expr,
									 colType,
									 "UNION/INTERSECT/EXCEPT");
		tlist = lappend(tlist, makeTargetEntry(resdom, expr));
		input_tlist = lnext(input_tlist);
		refnames_tlist = lnext(refnames_tlist);
422
	}
423 424

	if (flag >= 0)
425
	{
426
		/* Add a resjunk flag column */
427 428 429 430 431
		resdom = makeResdom((AttrNumber) resno++,
							INT4OID,
							-1,
							pstrdup("flag"),
							true);
432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451
		if (flag <= 1)
		{
			/* flag value is the given constant */
			expr = (Node *) makeConst(INT4OID,
									  sizeof(int4),
									  Int32GetDatum(flag),
									  false,
									  true,
									  false,
									  false);
		}
		else
		{
			/* flag value is being copied up from subplan */
			expr = (Node *) makeVar(0,
									resdom->resno,
									INT4OID,
									-1,
									0);
		}
452
		tlist = lappend(tlist, makeTargetEntry(resdom, expr));
453
	}
454

455 456
	return tlist;
}
457

458 459 460
/*
 * Does tlist have same datatypes as requested colTypes?
 *
461 462
 * Resjunk columns are ignored if junkOK is true; otherwise presence of
 * a resjunk column will always cause a 'false' result.
463 464
 */
static bool
465
tlist_same_datatypes(List *tlist, List *colTypes, bool junkOK)
466 467 468 469 470 471 472
{
	List	   *i;

	foreach(i, tlist)
	{
		TargetEntry *tle = (TargetEntry *) lfirst(i);

473 474
		if (tle->resdom->resjunk)
		{
475
			if (!junkOK)
476 477 478
				return false;
		}
		else
479 480 481 482 483 484 485 486 487 488 489
		{
			if (colTypes == NIL)
				return false;
			if (tle->resdom->restype != (Oid) lfirsti(colTypes))
				return false;
			colTypes = lnext(colTypes);
		}
	}
	if (colTypes != NIL)
		return false;
	return true;
490 491 492
}


493
/*
494
 * find_all_inheritors -
495 496
 *		Returns an integer list of relids including the given rel plus
 *		all relations that inherit from it, directly or indirectly.
497
 */
498
List *
499
find_all_inheritors(Oid parentrel)
500
{
501
	List	   *examined_relids = NIL;
502
	List	   *unexamined_relids = makeListi1(parentrel);
503 504

	/*
505 506 507
	 * While the queue of unexamined relids is nonempty, remove the first
	 * element, mark it examined, and find its direct descendants. NB:
	 * cannot use foreach(), since we modify the queue inside loop.
508
	 */
509
	while (unexamined_relids != NIL)
510
	{
511 512
		Oid			currentrel = lfirsti(unexamined_relids);
		List	   *currentchildren;
513

514 515 516
		unexamined_relids = lnext(unexamined_relids);
		examined_relids = lappendi(examined_relids, currentrel);
		currentchildren = find_inheritance_children(currentrel);
517

518
		/*
519 520 521 522 523
		 * Add to the queue only those children not already seen. This
		 * avoids making duplicate entries in case of multiple inheritance
		 * paths from the same parent.	(It'll also keep us from getting
		 * into an infinite loop, though theoretically there can't be any
		 * cycles in the inheritance graph anyway.)
524 525
		 */
		currentchildren = set_differencei(currentchildren, examined_relids);
526
		unexamined_relids = set_unioni(unexamined_relids, currentchildren);
527
	}
528

529
	return examined_relids;
530 531 532
}

/*
533 534 535 536 537 538
 * expand_inherted_rtentry
 *		Check whether a rangetable entry represents an inheritance set.
 *		If so, add entries for all the child tables to the query's
 *		rangetable, and return an integer list of RT indexes for the
 *		whole inheritance set (parent and children).
 *		If not, return NIL.
539
 *
540 541 542 543 544
 * When dup_parent is false, the initially given RT index is part of the
 * returned list (if any).  When dup_parent is true, the given RT index
 * is *not* in the returned list; a duplicate RTE will be made for the
 * parent table.
 *
545 546 547
 * A childless table is never considered to be an inheritance set; therefore
 * the result will never be a one-element list.  It'll be either empty
 * or have two or more elements.
548
 *
549 550 551 552
 * NOTE: after this routine executes, the specified RTE will always have
 * its inh flag cleared, whether or not there were any children.  This
 * ensures we won't expand the same RTE twice, which would otherwise occur
 * for the case of an inherited UPDATE/DELETE target relation.
553
 */
554
List *
555
expand_inherted_rtentry(Query *parse, Index rti, bool dup_parent)
556
{
557 558 559 560 561 562 563
	RangeTblEntry *rte = rt_fetch(rti, parse->rtable);
	Oid			parentOID = rte->relid;
	List	   *inhOIDs;
	List	   *inhRTIs;
	List	   *l;

	/* Does RT entry allow inheritance? */
564
	if (!rte->inh)
565 566 567 568 569
		return NIL;
	Assert(parentOID != InvalidOid && rte->subquery == NULL);
	/* Always clear the parent's inh flag, see above comments */
	rte->inh = false;
	/* Fast path for common case of childless table */
570
	if (!has_subclass(parentOID))
571 572 573 574
		return NIL;
	/* Scan for all members of inheritance set */
	inhOIDs = find_all_inheritors(parentOID);
	/*
575 576 577
	 * Check that there's at least one descendant, else treat as no-child
	 * case.  This could happen despite above has_subclass() check, if
	 * table once had a child but no longer does.
578 579 580 581
	 */
	if (lnext(inhOIDs) == NIL)
		return NIL;
	/* OK, it's an inheritance set; expand it */
582 583 584 585 586
	if (dup_parent)
		inhRTIs = NIL;
	else
		inhRTIs = makeListi1(rti); /* include original RTE in result */

587
	foreach(l, inhOIDs)
588
	{
589
		Oid			childOID = (Oid) lfirsti(l);
590
		RangeTblEntry *childrte;
591
		Index		childRTindex;
592

593 594
		/* parent will be in the list too; skip it if not dup requested */
		if (childOID == parentOID && !dup_parent)
595
			continue;
596

597
		/*
598 599 600 601
		 * Build an RTE for the child, and attach to query's rangetable
		 * list. We copy most fields of the parent's RTE, but replace
		 * relation real name and OID.	Note that inh will be false at
		 * this point.
602
		 */
603 604 605 606 607
		childrte = copyObject(rte);
		childrte->relname = get_rel_name(childOID);
		childrte->relid = childOID;
		parse->rtable = lappend(parse->rtable, childrte);
		childRTindex = length(parse->rtable);
608

609 610
		inhRTIs = lappendi(inhRTIs, childRTindex);
	}
611

612
	return inhRTIs;
613 614
}

615
/*
616 617 618
 * adjust_inherited_attrs
 *	  Copy the specified query or expression and translate Vars referring
 *	  to old_rt_index to refer to new_rt_index.
619
 *
620
 * We also adjust varattno to match the new table by column name, rather
621
 * than column number.	This hack makes it possible for child tables to have
622 623 624 625
 * different column positions for the "same" attribute as a parent, which
 * helps ALTER TABLE ADD COLUMN.  Unfortunately this isn't nearly enough to
 * make it work transparently; there are other places where things fall down
 * if children and parents don't have the same column numbers for inherited
626
 * attributes.	It'd be better to rip this code out and fix ALTER TABLE...
627
 */
628 629 630 631
Node *
adjust_inherited_attrs(Node *node,
					   Index old_rt_index, Oid old_relid,
					   Index new_rt_index, Oid new_relid)
632
{
633
	adjust_inherited_attrs_context context;
634

635 636 637 638 639 640
	/* Handle simple case simply... */
	if (old_rt_index == new_rt_index)
	{
		Assert(old_relid == new_relid);
		return copyObject(node);
	}
641

642 643
	context.old_rt_index = old_rt_index;
	context.new_rt_index = new_rt_index;
644 645
	context.old_relid = old_relid;
	context.new_relid = new_relid;
646

647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663
	/*
	 * Must be prepared to start with a Query or a bare expression tree.
	 */
	if (node && IsA(node, Query))
	{
		Query	   *query = (Query *) node;
		Query	   *newnode;

		FLATCOPY(newnode, query, Query);
		if (newnode->resultRelation == old_rt_index)
			newnode->resultRelation = new_rt_index;
		query_tree_mutator(newnode, adjust_inherited_attrs_mutator,
						   (void *) &context, false);
		return (Node *) newnode;
	}
	else
		return adjust_inherited_attrs_mutator(node, &context);
664 665
}

666 667 668
static Node *
adjust_inherited_attrs_mutator(Node *node,
							   adjust_inherited_attrs_context *context)
669
{
670
	if (node == NULL)
671
		return NULL;
672
	if (IsA(node, Var))
673
	{
674
		Var		   *var = (Var *) copyObject(node);
675

676 677
		if (var->varlevelsup == 0 &&
			var->varno == context->old_rt_index)
678
		{
679 680 681 682 683
			var->varno = context->new_rt_index;
			if (var->varattno > 0)
				var->varattno = get_attnum(context->new_relid,
										   get_attname(context->old_relid,
													   var->varattno));
684
		}
685
		return (Node *) var;
686
	}
687
	if (IsA(node, RangeTblRef))
688
	{
689
		RangeTblRef *rtr = (RangeTblRef *) copyObject(node);
690

691 692 693
		if (rtr->rtindex == context->old_rt_index)
			rtr->rtindex = context->new_rt_index;
		return (Node *) rtr;
694
	}
695

696 697 698
	/*
	 * We have to process RestrictInfo nodes specially: we do NOT want to
	 * copy the original subclauseindices list, since the new rel may have
699
	 * different indices.  The list will be rebuilt during later planning.
700 701 702
	 */
	if (IsA(node, RestrictInfo))
	{
703 704
		RestrictInfo *oldinfo = (RestrictInfo *) node;
		RestrictInfo *newinfo = makeNode(RestrictInfo);
705 706 707 708 709 710

		/* Copy all flat-copiable fields */
		memcpy(newinfo, oldinfo, sizeof(RestrictInfo));

		newinfo->clause = (Expr *)
			adjust_inherited_attrs_mutator((Node *) oldinfo->clause, context);
711

712
		newinfo->subclauseindices = NIL;
713 714
		newinfo->eval_cost = -1;		/* reset these too */
		newinfo->this_selec = -1;
715
		newinfo->left_pathkey = NIL;	/* and these */
716
		newinfo->right_pathkey = NIL;
717 718
		newinfo->left_bucketsize = -1;
		newinfo->right_bucketsize = -1;
719 720 721

		return (Node *) newinfo;
	}
722

723 724 725 726
	/*
	 * NOTE: we do not need to recurse into sublinks, because they should
	 * already have been converted to subplans before we see them.
	 */
727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749

	/*
	 * BUT: although we don't need to recurse into subplans, we do need to
	 * make sure that they are copied, not just referenced as
	 * expression_tree_mutator will do by default.  Otherwise we'll have the
	 * same subplan node referenced from each arm of the inheritance APPEND
	 * plan, which will cause trouble in the executor.  This is a kluge
	 * that should go away when we redesign querytrees.
	 */
	if (is_subplan(node))
	{
		SubPlan    *subplan;

		/* Copy the node and process subplan args */
		node = expression_tree_mutator(node, adjust_inherited_attrs_mutator,
									   (void *) context);
		/* Make sure we have separate copies of subplan and its rtable */
		subplan = (SubPlan *) ((Expr *) node)->oper;
		subplan->plan = copyObject(subplan->plan);
		subplan->rtable = copyObject(subplan->rtable);
		return node;
	}

750
	return expression_tree_mutator(node, adjust_inherited_attrs_mutator,
751
								   (void *) context);
752
}