prepunion.c 24.2 KB
Newer Older
1 2
/*-------------------------------------------------------------------------
 *
3
 * prepunion.c
4 5
 *	  Routines to plan set-operation and inheritance queries.  The filename
 *	  is a leftover from a time when only UNIONs were handled.
6
 *
Bruce Momjian's avatar
Add:  
Bruce Momjian committed
7 8
 * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
 * Portions Copyright (c) 1994, Regents of the University of California
9 10 11
 *
 *
 * IDENTIFICATION
12
 *	  $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.55 2000/11/09 02:46:17 tgl Exp $
13 14 15 16 17
 *
 *-------------------------------------------------------------------------
 */
#include "postgres.h"

18 19 20 21
#include <sys/types.h>

#include "catalog/pg_type.h"
#include "nodes/makefuncs.h"
22
#include "optimizer/clauses.h"
23
#include "optimizer/plancat.h"
24
#include "optimizer/planmain.h"
Bruce Momjian's avatar
Bruce Momjian committed
25 26
#include "optimizer/planner.h"
#include "optimizer/prep.h"
27
#include "optimizer/tlist.h"
Bruce Momjian's avatar
Bruce Momjian committed
28
#include "parser/parse_clause.h"
29
#include "parser/parse_coerce.h"
Bruce Momjian's avatar
Bruce Momjian committed
30 31
#include "parser/parsetree.h"
#include "utils/lsyscache.h"
32

33 34
typedef struct
{
35 36 37 38 39 40
	Index		rt_index;
	int			sublevels_up;
	Oid			old_relid;
	Oid			new_relid;
} fix_parsetree_attnums_context;

41
static Plan *recurse_set_operations(Node *setOp, Query *parse,
42 43
									List *colTypes, bool junkOK,
									int flag, List *refnames_tlist);
44 45 46 47 48 49 50 51
static Plan *generate_union_plan(SetOperationStmt *op, Query *parse,
								 List *refnames_tlist);
static Plan *generate_nonunion_plan(SetOperationStmt *op, Query *parse,
									List *refnames_tlist);
static List *recurse_union_children(Node *setOp, Query *parse,
									SetOperationStmt *top_union,
									List *refnames_tlist);
static List *generate_setop_tlist(List *colTypes, int flag,
52
								  bool hack_constants,
53 54
								  List *input_tlist,
								  List *refnames_tlist);
55
static bool tlist_same_datatypes(List *tlist, List *colTypes, bool junkOK);
56
static void fix_parsetree_attnums(Index rt_index, Oid old_relid,
57
					  Oid new_relid, Query *parsetree);
58 59
static bool fix_parsetree_attnums_walker(Node *node,
							 fix_parsetree_attnums_context *context);
60 61
static RangeTblEntry *new_rangetable_entry(Oid new_relid,
					 RangeTblEntry *old_entry);
62 63
static Append *make_append(List *appendplans, Index rt_index,
						   List *inheritrtable, List *tlist);
64 65


66
/*
67
 * plan_set_operations
68
 *
69
 *	  Plans the queries for a tree of set operations (UNION/INTERSECT/EXCEPT)
70
 *
71 72 73
 * This routine only deals with the setOperations tree of the given query.
 * Any top-level ORDER BY requested in parse->sortClause will be added on
 * back in union_planner.
74
 */
75
Plan *
76
plan_set_operations(Query *parse)
77
{
78 79 80 81 82 83 84 85 86
	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).
87
	 */
88 89 90 91 92 93 94
	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);
95

96 97 98
	/*
	 * Recurse on setOperations tree to generate plans for set ops.
	 * The final output plan should have just the column types shown
99 100
	 * 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).
101 102
	 */
	return recurse_set_operations((Node *) topop, parse,
103
								  topop->colTypes, true, -1,
104 105 106 107 108 109 110 111
								  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
112
 * junkOK: if true, child resjunk columns may be left in the result
113 114 115 116 117
 * 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,
118 119
					   List *colTypes, bool junkOK,
					   int flag, List *refnames_tlist)
120 121
{
	if (IsA(setOp, RangeTblRef))
122
	{
123 124 125 126 127
		RangeTblRef *rtr = (RangeTblRef *) setOp;
		RangeTblEntry *rte = rt_fetch(rtr->rtindex, parse->rtable);
		Query  *subquery = rte->subquery;
		Plan   *subplan,
			   *plan;
128

129 130 131 132 133 134 135 136 137 138
		Assert(subquery != NULL);
		/*
		 * Generate plan for primitive subquery
		 */
		subplan = subquery_planner(subquery,
								   -1.0 /* default case */ );
		/*
		 * Add a SubqueryScan with the caller-requested targetlist
		 */
		plan = (Plan *)
139
			make_subqueryscan(generate_setop_tlist(colTypes, flag, true,
140 141 142 143 144 145 146
												   subplan->targetlist,
												   refnames_tlist),
							  NIL,
							  rtr->rtindex,
							  subplan);
		copy_plan_costsize(plan, subplan);
		return plan;
147
	}
148
	else if (IsA(setOp, SetOperationStmt))
149
	{
150 151
		SetOperationStmt *op = (SetOperationStmt *) setOp;
		Plan   *plan;
152

153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
		/* 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);
		/*
		 * 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.
		 * 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.
		 */
171 172
		if (flag >= 0 ||
			! tlist_same_datatypes(plan->targetlist, colTypes, junkOK))
173
		{
174
			plan = (Plan *)
175
				make_result(generate_setop_tlist(colTypes, flag, false,
176 177 178 179
												 plan->targetlist,
												 refnames_tlist),
							NULL,
							plan);
180
		}
181
		return plan;
182 183 184
	}
	else
	{
185 186 187 188 189
		elog(ERROR, "recurse_set_operations: unexpected node %d",
			 (int) nodeTag(setOp));
		return NULL;			/* keep compiler quiet */
	}
}
190

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

	/*
	 * 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));
	/*
	 * Append the child results together.
	 *
	 * 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.
	 */
	plan = (Plan *)
		make_append(planlist,
					0,
					NIL,
222
					generate_setop_tlist(op->colTypes, -1, false,
223 224 225 226 227 228 229 230 231 232
									((Plan *) lfirst(planlist))->targetlist,
									refnames_tlist));
	/*
	 * For UNION ALL, we just need the Append plan.  For UNION,
	 * need to add Sort and Unique nodes to produce unique output.
	 */
	if (! op->all)
	{
		List   *tlist,
			   *sortList;
233

234 235 236 237 238 239 240
		tlist = new_unsorted_tlist(plan->targetlist);
		sortList = addAllTargetsToSortList(NIL, tlist);
		plan = make_sortplan(tlist, plan, sortList);
		plan = (Plan *) make_unique(tlist, plan, copyObject(sortList));
	}
	return plan;
}
241

242 243 244 245 246 247 248 249 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)
{
	Plan   *lplan,
		   *rplan,
		   *plan;
	List   *tlist,
		   *sortList;
	SetOpCmd cmd;

	/* Recurse on children, ensuring their outputs are marked */
	lplan = recurse_set_operations(op->larg, parse,
258
								   op->colTypes, false, 0,
259 260
								   refnames_tlist);
	rplan = recurse_set_operations(op->rarg, parse,
261
								   op->colTypes, false, 1,
262 263 264 265 266 267 268 269 270 271 272 273
								   refnames_tlist);
	/*
	 * Append the child results together.
	 *
	 * 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.
	 */
	plan = (Plan *)
		make_append(makeList2(lplan, rplan),
					0,
					NIL,
274
					generate_setop_tlist(op->colTypes, 0, false,
275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300
										 lplan->targetlist,
										 refnames_tlist));
	/*
	 * Sort the child results, then add a SetOp plan node to
	 * generate the correct output.
	 */
	tlist = new_unsorted_tlist(plan->targetlist);
	sortList = addAllTargetsToSortList(NIL, tlist);
	plan = make_sortplan(tlist, plan, sortList);
	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");
			cmd = SETOPCMD_INTERSECT; /* keep compiler quiet */
			break;
	}
	plan = (Plan *) make_setop(cmd, tlist, plan, sortList,
							   length(op->colTypes)+1);
	return plan;
}
301

302 303 304 305 306 307 308 309 310 311 312 313 314 315
/*
 * 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;
316

317 318 319
		if (op->op == top_union->op &&
			(op->all == top_union->all || op->all) &&
			equali(op->colTypes, top_union->colTypes))
320
		{
321 322 323 324 325
			/* Same UNION, so fold children into parent's subplan list */
			return nconc(recurse_union_children(op->larg, parse,
												top_union, refnames_tlist),
						 recurse_union_children(op->rarg, parse,
												top_union, refnames_tlist));
326
		}
327
	}
328 329 330 331 332 333 334 335 336 337
	/*
	 * Not same, so plan this child separately.
	 *
	 * 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.
	 */
338
	return makeList1(recurse_set_operations(setOp, parse,
339 340
											top_union->colTypes, false,
											-1, refnames_tlist));
341
}
342

343 344 345 346 347
/*
 * Generate targetlist for a set-operation plan node
 */
static List *
generate_setop_tlist(List *colTypes, int flag,
348
					 bool hack_constants,
349 350 351 352 353 354 355 356
					 List *input_tlist,
					 List *refnames_tlist)
{
	List	   *tlist = NIL;
	int			resno = 1;
	List	   *i;
	Resdom	   *resdom;
	Node	   *expr;
357

358 359 360 361 362 363 364 365 366 367
	foreach(i, colTypes)
	{
		Oid		colType = (Oid) lfirsti(i);
		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);
368
		/*
369 370 371 372 373 374 375
		 * 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
		 * rather than being referenced as subquery outputs.  This is mainly
		 * to ensure that when we try to coerce them to the output column's
376 377 378 379
		 * 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!
380
		 */
381 382 383 384 385
		resdom = makeResdom((AttrNumber) resno++,
							colType,
							-1,
							pstrdup(reftle->resdom->resname),
							false);
386
		if (hack_constants && inputtle->expr && IsA(inputtle->expr, Const))
387 388 389 390 391 392 393 394 395 396 397 398 399 400
			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);
401
	}
402 403

	if (flag >= 0)
404
	{
405 406 407 408 409 410 411 412 413 414 415 416 417 418
		/* Add a resjunk column yielding specified flag value */
		resdom = makeResdom((AttrNumber) resno++,
							INT4OID,
							-1,
							pstrdup("flag"),
							true);
		expr = (Node *) makeConst(INT4OID,
								  sizeof(int4),
								  Int32GetDatum(flag),
								  false,
								  true,
								  false,
								  false);
		tlist = lappend(tlist, makeTargetEntry(resdom, expr));
419
	}
420

421 422
	return tlist;
}
423

424 425 426
/*
 * Does tlist have same datatypes as requested colTypes?
 *
427 428
 * Resjunk columns are ignored if junkOK is true; otherwise presence of
 * a resjunk column will always cause a 'false' result.
429 430
 */
static bool
431
tlist_same_datatypes(List *tlist, List *colTypes, bool junkOK)
432 433 434 435 436 437 438
{
	List	   *i;

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

439 440 441 442 443 444
		if (tle->resdom->resjunk)
		{
			if (! junkOK)
				return false;
		}
		else
445 446 447 448 449 450 451 452 453 454 455
		{
			if (colTypes == NIL)
				return false;
			if (tle->resdom->restype != (Oid) lfirsti(colTypes))
				return false;
			colTypes = lnext(colTypes);
		}
	}
	if (colTypes != NIL)
		return false;
	return true;
456 457 458
}


459
/*
460
 * plan_inherit_queries
461
 *	  Plans the queries for an inheritance tree rooted at a parent relation.
462
 *
463
 * Inputs:
464
 *	root = parent parse tree
465 466
 *	tlist = target list for inheritance subqueries (not same as parent's!)
 *	rt_index = rangetable index for current inheritance item
467
 *	inheritors = list of OIDs of the target rel plus all its descendants
468 469 470 471 472 473
 *
 * Returns an APPEND node that forms the result of performing the given
 * query for each member relation of the inheritance group.
 *
 * If grouping, aggregation, or sorting is specified in the parent plan,
 * the subplans should not do any of those steps --- we must do those
474
 * operations just once above the APPEND node.	The given tlist has been
475 476
 * modified appropriately to remove group/aggregate expressions, but the
 * Query node still has the relevant fields set.  We remove them in the
477
 * copies used for subplans.
478 479
 *
 * NOTE: this can be invoked recursively if more than one inheritance wildcard
480
 * is present.	At each level of recursion, the first wildcard remaining in
481
 * the rangetable is expanded.
482 483 484 485 486
 *
 * NOTE: don't bother optimizing this routine for the case that the target
 * rel has no children.  We won't get here unless find_inheritable_rt_entry
 * found at least two members in the inheritance group, so an APPEND is
 * certainly necessary.
487
 */
488 489 490
Plan *
plan_inherit_queries(Query *root, List *tlist,
					 Index rt_index, List *inheritors)
491
{
492
	RangeTblEntry *rt_entry = rt_fetch(rt_index, root->rtable);
493 494
	List	   *union_plans = NIL;
	List	   *union_rtentries = NIL;
495
	List	   *save_tlist = root->targetList;
496
	double		tuple_fraction;
497
	List	   *i;
498

499 500
	/*
	 * Avoid making copies of the root's tlist, which we aren't going to
501
	 * use anyway (we are going to make copies of the passed tlist,
502 503
	 * instead).  This is purely a space-saving hack.  Note we restore
	 * the root's tlist before exiting.
504 505 506
	 */
	root->targetList = NIL;

507
	/*
508 509
	 * If we are going to need sorting or grouping at the top level, force
	 * lower-level planners to assume that all tuples will be retrieved.
510 511 512
	 */
	if (root->distinctClause || root->sortClause ||
		root->groupClause || root->hasAggs)
513
		tuple_fraction = 0.0;	/* will need all tuples from each subplan */
514
	else
515
		tuple_fraction = -1.0;	/* default behavior is OK (I think) */
516

517
	foreach(i, inheritors)
518
	{
519
		Oid			relid = lfirsti(i);
520

521
		/*
522
		 * Make a modifiable copy of the original query, and replace the
523 524 525 526
		 * target rangetable entry in it with a new one identifying this
		 * child table.  The new rtentry is marked inh = false --- this
		 * is essential to prevent infinite recursion when the subquery
		 * is rescanned by find_inheritable_rt_entry!
527 528
		 */
		Query	   *new_root = copyObject(root);
529 530
		RangeTblEntry *new_rt_entry = new_rangetable_entry(relid,
														   rt_entry);
531

532
		new_rt_entry->inh = false;
533
		rt_store(rt_index, new_root->rtable, new_rt_entry);
534

535
		/*
536 537
		 * Insert (a modifiable copy of) the desired simplified tlist into
		 * the subquery
538 539 540 541 542 543
		 */
		new_root->targetList = copyObject(tlist);

		/*
		 * Clear the sorting and grouping qualifications in the subquery,
		 * so that sorting will only be done once after append
544
		 */
545 546 547
		new_root->distinctClause = NIL;
		new_root->sortClause = NIL;
		new_root->groupClause = NIL;
Bruce Momjian's avatar
Bruce Momjian committed
548
		new_root->havingQual = NULL;
549 550
		new_root->limitOffset = NULL;	/* LIMIT's probably unsafe too */
		new_root->limitCount = NULL;
551
		new_root->hasAggs = false;		/* shouldn't be any left ... */
552

553 554 555 556 557
		/*
		 * Update attribute numbers in case child has different ordering
		 * of columns than parent (as can happen after ALTER TABLE).
		 *
		 * XXX This is a crock, and it doesn't really work.  It'd be better
558 559
		 * to fix ALTER TABLE to preserve consistency of attribute
		 * numbering.
560
		 */
Bruce Momjian's avatar
Bruce Momjian committed
561 562 563 564
		fix_parsetree_attnums(rt_index,
							  rt_entry->relid,
							  relid,
							  new_root);
565

566 567 568 569
		/*
		 * Plan the subquery by recursively calling union_planner().
		 * Add plan and child rtentry to lists for APPEND.
		 */
570 571
		union_plans = lappend(union_plans,
							  union_planner(new_root, tuple_fraction));
572 573
		union_rtentries = lappend(union_rtentries, new_rt_entry);
	}
574

575
	/* Restore root's tlist */
576 577
	root->targetList = save_tlist;

578 579 580 581 582
	/* Construct the finished Append plan. */
	return (Plan *) make_append(union_plans,
								rt_index,
								union_rtentries,
								((Plan *) lfirst(union_plans))->targetlist);
583 584
}

585
/*
586
 * find_all_inheritors -
587 588
 *		Returns an integer list of relids including the given rel plus
 *		all relations that inherit from it, directly or indirectly.
589
 */
590
List *
591
find_all_inheritors(Oid parentrel)
592
{
593 594
	List	   *examined_relids = NIL;
	List	   *unexamined_relids = lconsi(parentrel, NIL);
595 596

	/*
597 598 599
	 * 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.
600
	 */
601
	while (unexamined_relids != NIL)
602
	{
603 604
		Oid			currentrel = lfirsti(unexamined_relids);
		List	   *currentchildren;
605

606 607 608
		unexamined_relids = lnext(unexamined_relids);
		examined_relids = lappendi(examined_relids, currentrel);
		currentchildren = find_inheritance_children(currentrel);
609

610
		/*
611 612 613 614 615
		 * 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.)
616 617
		 */
		currentchildren = set_differencei(currentchildren, examined_relids);
618
		unexamined_relids = set_unioni(unexamined_relids, currentchildren);
619
	}
620

621
	return examined_relids;
622 623 624
}

/*
625
 * find_inheritable_rt_entry -
626
 *		Given a rangetable, find the first rangetable entry that represents
627
 *		an inheritance set.
628
 *
629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646
 *		If successful, set *rt_index to the index (1..n) of the entry,
 *		set *inheritors to a list of the relation OIDs of the set,
 *		and return TRUE.
 *
 *		If there is no entry that requires inheritance processing,
 *		return FALSE.
 *
 * NOTE: We return the inheritors list so that plan_inherit_queries doesn't
 * have to compute it again.
 *
 * NOTE: We clear the inh flag in any entries that have it set but turn
 * out not to have any actual inheritance children.  This is an efficiency
 * hack to avoid having to repeat the inheritance checks if the list is
 * scanned again (as will happen during expansion of any subsequent entry
 * that does have inheritance children).  Although modifying the input
 * rangetable in-place may seem uncool, there's no reason not to do it,
 * since any re-examination of the entry would just come to the same
 * conclusion that the table has no children.
647
 */
648 649 650 651
bool
find_inheritable_rt_entry(List *rangetable,
						  Index *rt_index,
						  List **inheritors)
652
{
653
	Index		count = 0;
654
	List	   *temp;
655 656 657

	foreach(temp, rangetable)
	{
658 659
		RangeTblEntry  *rt_entry = (RangeTblEntry *) lfirst(temp);
		List		   *inhs;
660 661

		count++;
662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686
		/* Ignore non-inheritable RT entries */
		if (! rt_entry->inh)
			continue;
		/* Fast path for common case of childless table */
		if (! has_subclass(rt_entry->relid))
		{
			rt_entry->inh = false;
			continue;
		}
		/* Scan for all members of inheritance set */
		inhs = find_all_inheritors(rt_entry->relid);
		/*
		 * 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.
		 */
		if (lnext(inhs) == NIL)
		{
			rt_entry->inh = false;
			continue;
		}
		/* OK, found our boy */
		*rt_index = count;
		*inheritors = inhs;
		return true;
687 688
	}

689
	return false;
690 691
}

692
/*
693 694 695
 * new_rangetable_entry -
 *		Replaces the name and relid of 'old_entry' with the values for
 *		'new_relid'.
696
 *
697
 *		Returns a copy of 'old_entry' with the parameters substituted.
698 699
 */
static RangeTblEntry *
700
new_rangetable_entry(Oid new_relid, RangeTblEntry *old_entry)
701
{
702
	RangeTblEntry *new_entry = copyObject(old_entry);
703

704 705
	/* Replace relation real name and OID, but not the reference name */
	new_entry->relname = get_rel_name(new_relid);
706
	new_entry->relid = new_relid;
707
	return new_entry;
708 709
}

710
/*
711 712 713 714
 * fix_parsetree_attnums
 *	  Replaces attribute numbers from the relation represented by
 *	  'old_relid' in 'parsetree' with the attribute numbers from
 *	  'new_relid'.
715
 *
716
 * The parsetree is MODIFIED IN PLACE.	This is OK only because
717
 * plan_inherit_queries made a copy of the tree for us to hack upon.
718
 */
719 720 721 722 723
static void
fix_parsetree_attnums(Index rt_index,
					  Oid old_relid,
					  Oid new_relid,
					  Query *parsetree)
724
{
725
	fix_parsetree_attnums_context context;
726

727 728
	if (old_relid == new_relid)
		return;					/* no work needed for parent rel itself */
729

730 731 732 733
	context.rt_index = rt_index;
	context.old_relid = old_relid;
	context.new_relid = new_relid;
	context.sublevels_up = 0;
734

735 736
	query_tree_walker(parsetree,
					  fix_parsetree_attnums_walker,
737 738
					  (void *) &context,
					  true);
739 740
}

741
/*
742
 * Adjust varnos for child tables.	This routine makes it possible for
743 744 745 746 747 748 749
 * child tables to have 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 attributes.  It'd be better to rip this code out and fix
 * ALTER TABLE...
 */
750
static bool
751 752
fix_parsetree_attnums_walker(Node *node,
							 fix_parsetree_attnums_context *context)
753
{
754
	if (node == NULL)
755 756
		return false;
	if (IsA(node, Var))
757
	{
758
		Var		   *var = (Var *) node;
759

760 761 762 763 764 765 766 767 768 769
		if (var->varlevelsup == context->sublevels_up &&
			var->varno == context->rt_index &&
			var->varattno > 0)
		{
			var->varattno = get_attnum(context->new_relid,
									   get_attname(context->old_relid,
												   var->varattno));
		}
		return false;
	}
770
	if (IsA(node, Query))
771
	{
772 773
		/* Recurse into subselects */
		bool		result;
774

775
		context->sublevels_up++;
776 777
		result = query_tree_walker((Query *) node,
								   fix_parsetree_attnums_walker,
778 779
								   (void *) context,
								   true);
780
		context->sublevels_up--;
781
		return result;
782 783 784
	}
	return expression_tree_walker(node, fix_parsetree_attnums_walker,
								  (void *) context);
785 786
}

787
static Append *
788
make_append(List *appendplans,
789
			Index rt_index,
790
			List *inheritrtable,
791
			List *tlist)
792
{
793
	Append	   *node = makeNode(Append);
794
	List	   *subnode;
795

796 797 798
	node->appendplans = appendplans;
	node->inheritrelid = rt_index;
	node->inheritrtable = inheritrtable;
799 800
	node->plan.startup_cost = 0;
	node->plan.total_cost = 0;
801 802
	node->plan.plan_rows = 0;
	node->plan.plan_width = 0;
803
	foreach(subnode, appendplans)
804
	{
805
		Plan	   *subplan = (Plan *) lfirst(subnode);
806

807
		if (subnode == appendplans)		/* first node? */
808 809
			node->plan.startup_cost = subplan->startup_cost;
		node->plan.total_cost += subplan->total_cost;
810 811 812 813
		node->plan.plan_rows += subplan->plan_rows;
		if (node->plan.plan_width < subplan->plan_width)
			node->plan.plan_width = subplan->plan_width;
	}
814 815 816 817 818 819
	node->plan.state = (EState *) NULL;
	node->plan.targetlist = tlist;
	node->plan.qual = NIL;
	node->plan.lefttree = (Plan *) NULL;
	node->plan.righttree = (Plan *) NULL;

820
	return node;
821
}